diff options
Diffstat (limited to 'railties')
41 files changed, 522 insertions, 363 deletions
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md index 0c59f59917..b05ac21b49 100644 --- a/railties/CHANGELOG.md +++ b/railties/CHANGELOG.md @@ -30,6 +30,16 @@ 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) ## diff --git a/railties/guides/code/getting_started/app/controllers/posts_controller.rb b/railties/guides/code/getting_started/app/controllers/posts_controller.rb index 7e903c984c..1581d4eb16 100644 --- a/railties/guides/code/getting_started/app/controllers/posts_controller.rb +++ b/railties/guides/code/getting_started/app/controllers/posts_controller.rb @@ -62,7 +62,7 @@ class PostsController < ApplicationController respond_to do |format| if @post.update_attributes(params[:post]) format.html { redirect_to @post, notice: 'Post was successfully updated.' } - format.json { head :ok } + format.json { head :no_content } else format.html { render action: "edit" } format.json { render json: @post.errors, status: :unprocessable_entity } @@ -78,7 +78,7 @@ class PostsController < ApplicationController respond_to do |format| format.html { redirect_to posts_url } - format.json { head :ok } + format.json { head :no_content } end end end diff --git a/railties/guides/code/getting_started/config/application.rb b/railties/guides/code/getting_started/config/application.rb index e914b5a80e..e16da30f72 100644 --- a/railties/guides/code/getting_started/config/application.rb +++ b/railties/guides/code/getting_started/config/application.rb @@ -39,6 +39,11 @@ module Blog # 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 diff --git a/railties/guides/code/getting_started/config/environments/test.rb b/railties/guides/code/getting_started/config/environments/test.rb index 833241ace3..08697cbbc9 100644 --- a/railties/guides/code/getting_started/config/environments/test.rb +++ b/railties/guides/code/getting_started/config/environments/test.rb @@ -29,11 +29,6 @@ Blog::Application.configure do # 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 - # Print deprecation notices to the stderr config.active_support.deprecation = :stderr diff --git a/railties/guides/rails_guides/generator.rb b/railties/guides/rails_guides/generator.rb index 4682ead66e..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) diff --git a/railties/guides/source/action_mailer_basics.textile b/railties/guides/source/action_mailer_basics.textile index ad5b848d2c..26c95be031 100644 --- a/railties/guides/source/action_mailer_basics.textile +++ b/railties/guides/source/action_mailer_basics.textile @@ -362,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. diff --git a/railties/guides/source/action_view_overview.textile b/railties/guides/source/action_view_overview.textile index 40cde6ad84..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 diff --git a/railties/guides/source/active_record_querying.textile b/railties/guides/source/active_record_querying.textile index 2e1f89cb78..ad12dca7e8 100644 --- a/railties/guides/source/active_record_querying.textile +++ b/railties/guides/source/active_record_querying.textile @@ -8,6 +8,7 @@ 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. @@ -201,7 +202,7 @@ end 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. -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. +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. @@ -435,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("DISTINCT(name)") +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> +query = Client.select(:name).uniq +# => Returns unique names + +query.uniq(false) +# => Returns all names, even if there are duplicates </ruby> h3. Limit and Offset @@ -741,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 @@ -1258,3 +1275,67 @@ Client.sum("orders_count") </ruby> For options, please see the parent section, "Calculations":#calculations. + +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> +<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> + 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> +<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) +<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. diff --git a/railties/guides/source/active_record_validations_callbacks.textile b/railties/guides/source/active_record_validations_callbacks.textile index 665e7f9ccc..a27c292a4c 100644 --- a/railties/guides/source/active_record_validations_callbacks.textile +++ b/railties/guides/source/active_record_validations_callbacks.textile @@ -796,17 +796,9 @@ person.errors.size # => 0 h3. Displaying Validation Errors in the View -Rails maintains an official plugin, DynamicForm, 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. +"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 plugin - -<shell> -$ rails plugin install git://github.com/joelmoss/dynamic_form.git -</shell> - -h4. Installing as a Gem - -Add this line in your Gemfile: +You can install it as a gem by adding this line to your Gemfile: <ruby> gem "dynamic_form" @@ -986,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 they are registered simply by defining them as regular methods with predefined names. 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, which would otherwise significantly slow 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 diff --git a/railties/guides/source/asset_pipeline.textile b/railties/guides/source/asset_pipeline.textile index 6ff5e87b6d..3681501293 100644 --- a/railties/guides/source/asset_pipeline.textile +++ b/railties/guides/source/asset_pipeline.textile @@ -438,7 +438,7 @@ location ~ ^/assets/ { } </plain> -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. +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+: diff --git a/railties/guides/source/association_basics.textile b/railties/guides/source/association_basics.textile index 6829eb8ef4..451653655f 100644 --- a/railties/guides/source/association_basics.textile +++ b/railties/guides/source/association_basics.textile @@ -1234,7 +1234,7 @@ 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 => proc { "orders.created_at > #{10.hours.ago.to_s(:db).inspect}" } + :conditions => proc { ["orders.created_at > ?, 10.hours.ago] } end </ruby> diff --git a/railties/guides/source/caching_with_rails.textile b/railties/guides/source/caching_with_rails.textile index 4273d0dd64..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+. @@ -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. diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile index bb494fbd33..cd6e7d116e 100644 --- a/railties/guides/source/configuring.textile +++ b/railties/guides/source/configuring.textile @@ -40,6 +40,8 @@ Rails will use that particular setting to configure Active Record. h4. Rails General Configuration +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> diff --git a/railties/guides/source/contributing_to_ruby_on_rails.textile b/railties/guides/source/contributing_to_ruby_on_rails.textile index 5848172510..37ead2bff2 100644 --- a/railties/guides/source/contributing_to_ruby_on_rails.textile +++ b/railties/guides/source/contributing_to_ruby_on_rails.textile @@ -87,21 +87,21 @@ $ 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 @@ -111,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 @@ -130,7 +130,7 @@ The gem +sqlite3-ruby+ does not belong to the "db" group indeed, if you followed <shell> $ cd activerecord -$ rake test_sqlite3 +$ bundle exec rake test_sqlite3 </shell> h5. MySQL and PostgreSQL @@ -195,12 +195,12 @@ 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 @@ -215,7 +215,7 @@ TIP: You may want to "put your git branch name in your shell prompt":http://qugs 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 diff --git a/railties/guides/source/engines.textile b/railties/guides/source/engines.textile index da56f3d0ed..694b36bea1 100644 --- a/railties/guides/source/engines.textile +++ b/railties/guides/source/engines.textile @@ -506,6 +506,10 @@ 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: @@ -542,6 +546,14 @@ Go ahead and try to create a new post. You will see that it works exactly in the 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. diff --git a/railties/guides/source/getting_started.textile b/railties/guides/source/getting_started.textile index bf6104b96b..fde83ae730 100644 --- a/railties/guides/source/getting_started.textile +++ b/railties/guides/source/getting_started.textile @@ -46,6 +46,10 @@ 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 @@ -215,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. @@ -233,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.1" 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: @@ -261,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 @@ -399,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 @@ -480,7 +492,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. @@ -501,8 +513,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 @@ -530,7 +541,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: @@ -544,21 +555,21 @@ folders, and edit <tt>config/routes.rb</tt>. Here's a quick overview of what it |_.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/scaffolds.css.scss |Cascading style sheet to make the scaffolded views look better| -|app/assets/stylesheets/posts.css.scss |Cascading style sheet for the posts controller| -|app/assets/javascripts/posts.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 @@ -596,11 +607,11 @@ end </ruby> The above migration creates a method named +change+ which will be called when you -run this migration. The action defined in that method is also reversible, which +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 -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. @@ -620,7 +631,7 @@ table. == CreatePosts: migrated (0.0020s) =========================================== </shell> -NOTE. Because by default you're working in the development environment, this +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 another environment, for instance in production, you must explicitly pass it when @@ -691,7 +702,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 @@ -716,10 +728,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 @@ -729,13 +739,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> @@ -749,9 +760,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. @@ -802,7 +812,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,9 +826,10 @@ 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> @@ -996,7 +1007,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> @@ -1060,7 +1071,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, @@ -1089,7 +1100,7 @@ def destroy respond_to do |format| format.html { redirect_to posts_url } - format.json { head :ok } + format.json { head :no_content } end end </ruby> @@ -1101,7 +1112,7 @@ 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. @@ -1120,9 +1131,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+: @@ -1169,8 +1182,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 @@ -1243,13 +1258,14 @@ $ 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 diff --git a/railties/guides/source/i18n.textile b/railties/guides/source/i18n.textile index 2d4cc13571..e9477e84cf 100644 --- a/railties/guides/source/i18n.textile +++ b/railties/guides/source/i18n.textile @@ -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 diff --git a/railties/guides/source/initialization.textile b/railties/guides/source/initialization.textile index f88405a2fd..036b356a37 100644 --- a/railties/guides/source/initialization.textile +++ b/railties/guides/source/initialization.textile @@ -525,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+ @@ -575,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+. @@ -598,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+ @@ -624,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+ @@ -682,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+. @@ -698,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. @@ -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: diff --git a/railties/guides/source/migrations.textile b/railties/guides/source/migrations.textile index 23e36b39f9..5b52a93853 100644 --- a/railties/guides/source/migrations.textile +++ b/railties/guides/source/migrations.textile @@ -658,7 +658,7 @@ In many ways this is exactly what it is. This file is created by inspecting the 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+. -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/#{Rails.env}_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. +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 diff --git a/railties/guides/source/performance_testing.textile b/railties/guides/source/performance_testing.textile index f3ea7e38bc..2440927542 100644 --- a/railties/guides/source/performance_testing.textile +++ b/railties/guides/source/performance_testing.textile @@ -447,7 +447,7 @@ 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. diff --git a/railties/guides/source/routing.textile b/railties/guides/source/routing.textile index f281009fee..29c729592b 100644 --- a/railties/guides/source/routing.textile +++ b/railties/guides/source/routing.textile @@ -620,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 diff --git a/railties/guides/source/testing.textile b/railties/guides/source/testing.textile index 2341a3522c..5dbbe2c0f0 100644 --- a/railties/guides/source/testing.textile +++ b/railties/guides/source/testing.textile @@ -927,7 +927,7 @@ 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] diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index 82fffe86bb..817fa39cab 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -166,7 +166,7 @@ module Rails middleware.use ::Rack::MethodOverride 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, config.consider_all_requests_local + 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/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/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 1c9627734e..d652c6b7fe 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, diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb index 10fdfdd8a9..3fbde0d989 100644 --- a/railties/lib/rails/generators/app_base.rb +++ b/railties/lib/rails/generators/app_base.rb @@ -139,11 +139,13 @@ module Rails <<-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 @@ -197,6 +199,7 @@ module Rails group :assets do 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 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 13fbe9e526..40fd843b1b 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/application.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/application.rb @@ -49,6 +49,11 @@ 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 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 80198cc21e..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,11 +29,6 @@ # 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 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 4baa2110e7..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 @@ -39,7 +39,7 @@ module Rails end def gitignore - copy_file "gitignore", ".gitignore" + template "gitignore", ".gitignore" end def lib @@ -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/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/tasks/documentation.rake b/railties/lib/rails/tasks/documentation.rake index ca8875ad9b..1e7da5ccae 100644 --- a/railties/lib/rails/tasks/documentation.rake +++ b/railties/lib/rails/tasks/documentation.rake @@ -66,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/test_unit/testing.rake b/railties/lib/rails/test_unit/testing.rake index 3d87529ad4..52d92cdd96 100644 --- a/railties/lib/rails/test_unit/testing.rake +++ b/railties/lib/rails/test_unit/testing.rake @@ -123,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/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/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/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb index 955ed09361..a1bd2fbaa5 100644 --- a/railties/test/generators/app_generator_test.rb +++ b/railties/test/generators/app_generator_test.rb @@ -208,6 +208,13 @@ 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' diff --git a/railties/test/generators/plugin_new_generator_test.rb b/railties/test/generators/plugin_new_generator_test.rb index 9183945619..826eac904e 100644 --- a/railties/test/generators/plugin_new_generator_test.rb +++ b/railties/test/generators/plugin_new_generator_test.rb @@ -37,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/ @@ -236,6 +242,14 @@ 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"] |