diff --git a/actionpack/lib/action_controller/caching/sweeping.rb b/actionpack/lib/action_controller/caching/sweeping.rb index 73291ce083e5c6e020fcd79e9c296229ae0a50b1..271d5f06b8b43cba554490edbf2c01e0897e3b22 100644 --- a/actionpack/lib/action_controller/caching/sweeping.rb +++ b/actionpack/lib/action_controller/caching/sweeping.rb @@ -1,6 +1,6 @@ module ActionController #:nodoc: module Caching - # Sweepers are the terminators of the caching world and responsible for expiring caches when model objects change. + # Sweepers are the terminators of the caching world and responsible for expiring caches when Active Record objects change. # They do this by being half-observers, half-filters and implementing callbacks for both roles. A Sweeper example: # # class ListSweeper < ActionController::Caching::Sweeper diff --git a/activemodel/lib/active_model/validations/validates.rb b/activemodel/lib/active_model/validations/validates.rb index eb6e604851dd61d7fff795b558418a2bd2ca777f..03046a543a3248cf4a42a8bb7d1886f997c9f4a5 100644 --- a/activemodel/lib/active_model/validations/validates.rb +++ b/activemodel/lib/active_model/validations/validates.rb @@ -94,10 +94,10 @@ module ClassMethods # validates :token, uniqueness: true, strict: TokenGenerationException # # - # Finally, the options +:if+, +:unless+, +:on+, +:allow_blank+, +:allow_nil+ - # and +:strict+ can be given to one specific validator, as a hash: + # Finally, the options +:if+, +:unless+, +:on+, +:allow_blank+, +:allow_nil+, +:strict+ + # and +:message+ can be given to one specific validator, as a hash: # - # validates :password, presence: { if: :password_required? }, confirmation: true + # validates :password, presence: { if: :password_required?, message: 'is forgotten.' }, confirmation: true def validates(*attributes) defaults = attributes.extract_options!.dup validations = defaults.slice!(*_validates_default_keys) diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb index 7a3d9bfd3e859142599fbe3bbaa9c1e5dbb27689..bf08459b3b37649aa760e0585da5c320c29a2caf 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb @@ -494,7 +494,7 @@ def checkout_and_verify(c) # # Normally there is only a single ConnectionHandler instance, accessible via # ActiveRecord::Base.connection_handler. Active Record models use this to - # determine that connection pool that they should use. + # determine the connection pool that they should use. class ConnectionHandler def initialize @owner_to_pool = Hash.new { |h,k| h[k] = {} } diff --git a/activerecord/lib/active_record/store.rb b/activerecord/lib/active_record/store.rb index 25f528498e7c8742cf2453220ab09c9401a5dc04..8ea0ea239ff85a0ffb5f2d1947b0b615398b7457 100644 --- a/activerecord/lib/active_record/store.rb +++ b/activerecord/lib/active_record/store.rb @@ -82,7 +82,7 @@ def initialize_store_attribute(store_attribute) attribute end - class IndifferentCoder + class IndifferentCoder # :nodoc: def initialize(coder_or_class_name) @coder = if coder_or_class_name.respond_to?(:load) && coder_or_class_name.respond_to?(:dump) diff --git a/guides/source/4_0_release_notes.textile b/guides/source/4_0_release_notes.textile index 0e03779e0d3078be599b1853b132246e613b9e24..fc922b04b774ea567e38e84232298e4590378620 100644 --- a/guides/source/4_0_release_notes.textile +++ b/guides/source/4_0_release_notes.textile @@ -116,6 +116,20 @@ h3. Action Mailer * Asynchronously send messages via the Rails Queue. +* Delivery Options (such as SMTP Settings) can now be set dynamically per mailer action. + +Delivery options are set via :delivery_method_options key on mail. + + +def welcome_mailer(user,company) + mail to: user.email, + subject: "Welcome!", + delivery_method_options: {user_name: company.smtp_user, + password: company.smtp_password, + address: company.smtp_server} +end + + h3. Action Pack h4. Action Controller diff --git a/guides/source/action_mailer_basics.textile b/guides/source/action_mailer_basics.textile index bca403ae72e5313aec50b9b37466d2458832eedb..5f09b8e41003fefdad76dc250709eca4070d58bc 100644 --- a/guides/source/action_mailer_basics.textile +++ b/guides/source/action_mailer_basics.textile @@ -410,6 +410,21 @@ end The above will send a multipart email with an attachment, properly nested with the top level being multipart/mixed and the first part being a multipart/alternative containing the plain text and HTML email messages. +h5. Sending Emails with Dynamic Delivery Options + +If you wish to override the default delivery options (e.g. SMTP credentials) while delivering emails, you can do this using +delivery_method_options+ in the mailer action. + + +class UserMailer < ActionMailer::Base + def welcome_email(user,company) + @user = user + @url = user_url(@user) + delivery_options = { user_name: company.smtp_user, password: company.smtp_password, address: company.smtp_host } + mail(to: user.email, subject: "Please see the Terms and Conditions attached", delivery_method_options: delivery_options) + end +end + + h3. Receiving Emails Receiving and parsing emails with Action Mailer can be a rather complex endeavor. Before your email reaches your Rails app, you would have had to configure your system to somehow forward emails to your app, which needs to be listening for that. So, to receive emails in your Rails app you'll need to: diff --git a/guides/source/action_view_overview.textile b/guides/source/action_view_overview.textile index 1fd98a5bbe139cdac6578c13b50210e551a85561..33ae7f6933a8ef1dae01ec81640dfa9dc84b0b00 100644 --- a/guides/source/action_view_overview.textile +++ b/guides/source/action_view_overview.textile @@ -1211,7 +1211,7 @@ Sample usage (selecting the associated Authors for an instance of Post, +@post+) collection_check_boxes(:post, :author_ids, Author.all, :id, :name_with_initial) -If @post.author_ids is [1], this would return: +If @post.author_ids is [1], this would return: diff --git a/guides/source/active_record_querying.textile b/guides/source/active_record_querying.textile index 80c9260a0d5e8c4c79c5057b68dc3389b23a46e7..96ae5b29720d82ae9d4790ed7689573f5f5bb849 100644 --- a/guides/source/active_record_querying.textile +++ b/guides/source/active_record_querying.textile @@ -266,7 +266,7 @@ SELECT * FROM clients WHERE (clients.id IN (1,10)) WARNING: Model.find(array_of_primary_key) will raise an +ActiveRecord::RecordNotFound+ exception unless a matching record is found for all of the supplied primary keys. -h5. take +h5(#take-n-objects). take Model.take(limit) retrieves the first number of records specified by +limit+ without any explicit ordering: @@ -282,7 +282,7 @@ The SQL equivalent of the above is: SELECT * FROM clients LIMIT 2 -h5. first +h5(#first-n-objects). first Model.first(limit) finds the first number of records specified by +limit+ ordered by primary key: @@ -298,7 +298,7 @@ The SQL equivalent of the above is: SELECT * FROM clients LIMIT 2 -h5. last +h5(#last-n-objects). last Model.last(limit) finds the number of records specified by +limit+ ordered by primary key in descending order: @@ -1144,7 +1144,8 @@ category.posts.created_before(time) h4. Applying a default scope -If we wish for a scope to be applied across all queries to the model we can use the +default_scope+ method within the model itself. +If we wish for a scope to be applied across all queries to the model we can use the ++default_scope+ method within the model itself. class Client < ActiveRecord::Base @@ -1152,15 +1153,29 @@ class Client < ActiveRecord::Base end -When queries are executed on this model, the SQL query will now look something like this: +When queries are executed on this model, the SQL query will now look something like +this: SELECT * FROM clients WHERE removed_at IS NULL +If you need to do more complex things with a default scope, you can alternatively +define it as a class method: + + +class Client < ActiveRecord::Base + def self.default_scope + # Should return an ActiveRecord::Relation. + end +end + + h4. Removing all scoping -If we wish to remove scoping for any reason we can use the +unscoped+ method. This is especially useful if a +default_scope+ is specified in the model and should not be applied for this particular query. +If we wish to remove scoping for any reason we can use the +unscoped+ method. This is +especially useful if a +default_scope+ is specified in the model and should not be +applied for this particular query. Client.unscoped.all @@ -1168,6 +1183,15 @@ Client.unscoped.all This method removes all scoping and will do a normal query on the table. +Note that chaining +unscoped+ with a +scope+ does not work. In these cases, it is +recommended that you use the block form of +unscoped+: + + +Client.unscoped { + Client.created_before(Time.zome.now) +} + + h3. Dynamic Finders For every field (also known as an attribute) you define in your table, Active Record provides a finder method. If you have a field called +first_name+ on your +Client+ model for example, you get +find_by_first_name+ and +find_all_by_first_name+ for free from Active Record. If you have a +locked+ field on the +Client+ model, you also get +find_by_locked+ and +find_all_by_locked+ methods. @@ -1218,7 +1242,7 @@ Client.find_or_create_by_first_name(:first_name => "Andy", :locked => false) 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!+ +h4(#first_or_create_bang). +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 diff --git a/guides/source/association_basics.textile b/guides/source/association_basics.textile index d4c0a1ba7424d6d9d3ff606b77e45544be0a59cc..151752eee9d7723ba28f2baeaa8589595dc7f4fb 100644 --- a/guides/source/association_basics.textile +++ b/guides/source/association_basics.textile @@ -88,6 +88,8 @@ end !images/belongs_to.png(belongs_to Association Diagram)! +NOTE: +belongs_to+ associations _must_ use the singular term. If you used the pluralized form in the above example for the +customer+ association in the +Order+ model, you would be told that there was an "uninitialized constant Order::Customers". This is because Rails automatically infers the class name from the association name. If the association name is wrongly pluralized, then the inferred class will be wrongly pluralized too. + h4. The +has_one+ Association A +has_one+ association also sets up a one-to-one connection with another model, but with somewhat different semantics (and consequences). This association indicates that each instance of a model contains or possesses one instance of another model. For example, if each supplier in your application has only one account, you'd declare the supplier model like this: diff --git a/guides/source/caching_with_rails.textile b/guides/source/caching_with_rails.textile index 815b2ef9c2e2111aaffbcbf4c04bf900982ae0af..712440da32d76f5641a5031193127c548302a166 100644 --- a/guides/source/caching_with_rails.textile +++ b/guides/source/caching_with_rails.textile @@ -173,7 +173,9 @@ expire_fragment('all_available_products') h4. Sweepers -Cache sweeping is a mechanism which allows you to get around having a ton of +expire_{page,action,fragment}+ calls in your code. It does this by moving all the work required to expire cached content into an +ActionController::Caching::Sweeper+ subclass. This class is an observer and looks for changes to an object via callbacks, and when a change occurs it expires the caches associated with that object in an around or after filter. +Cache sweeping is a mechanism which allows you to get around having a ton of +expire_{page,action,fragment}+ calls in your code. It does this by moving all the work required to expire cached content into an +ActionController::Caching::Sweeper+ subclass. This class is an observer and looks for changes to an Active Record object via callbacks, and when a change occurs it expires the caches associated with that object in an around or after filter. + +TIP: Sweepers rely on the use of Active Record and Active Record Observers. The object you are observing must be an Active Record model. Continuing with our Product controller example, we could rewrite it with a sweeper like this: @@ -353,7 +355,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 +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. +This cache store uses Danga's +memcached+ server to provide a centralized cache for your application. Rails uses the bundled +dalli+ 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. @@ -439,7 +441,7 @@ class ProductsController < ApplicationController # If the request is stale according to the given timestamp and etag value # (i.e. it needs to be processed again) then execute this block - if stale?(:last_modified => @product.updated_at.utc, :etag => @product) + if stale?(:last_modified => @product.updated_at.utc, :etag => @product.cache_key) respond_to do |wants| # ... normal response processing end @@ -453,6 +455,17 @@ class ProductsController < ApplicationController end +Instead of a options hash, you can also simply pass in a model, Rails will use the +updated_at+ and +cache_key+ methods for setting +last_modified+ and +etag+: + + +class ProductsController < ApplicationController + def show + @product = Product.find(params[:id]) + respond_with(@product) if stale?(@product) + end +end + + If you don't have any special response processing and are using the default rendering mechanism (i.e. you're not using respond_to or calling render yourself) then you’ve got an easy helper in fresh_when: diff --git a/guides/source/configuring.textile b/guides/source/configuring.textile index 9db375c2ca4cf67207135b110e7dfd1b8e786747..dd84754b2203eecf9db18f0936ad8bc8932d3176 100644 --- a/guides/source/configuring.textile +++ b/guides/source/configuring.textile @@ -388,7 +388,7 @@ And can reference in the view with the following code: <%= render @post %> - + The default setting is +true+, which uses the partial at +/admin/posts/_post.erb+. Setting the value to +false+ would render +/posts/_post.erb+, which is the same behavior as rendering from a non-namespaced controller such as +PostsController+. diff --git a/guides/source/debugging_rails_applications.textile b/guides/source/debugging_rails_applications.textile index 667f2d21409cd4735e67140d3b6f66c20e1bea27..a5a22a8a8fc9a3f450b83aa7d8104e74d4161860 100644 --- a/guides/source/debugging_rails_applications.textile +++ b/guides/source/debugging_rails_applications.textile @@ -191,6 +191,17 @@ Completed in 0.01224 (81 reqs/sec) | DB: 0.00044 (3%) | 302 Found [http://localh Adding extra logging like this makes it easy to search for unexpected or unusual behavior in your logs. If you add extra logging, be sure to make sensible use of log levels, to avoid filling your production logs with useless trivia. +h4. Tagged Logging + +When running multi-user, multi-account applications, it’s often useful to be able to filter the logs using some custom rules. +TaggedLogging+ in Active Support helps in doing exactly that by stamping log lines with subdomains, request ids, and anything else to aid debugging such applications. + + +logger = ActiveSupport::TaggedLogging.new(Logger.new(STDOUT)) +logger.tagged("BCX") { logger.info "Stuff" } # Logs "[BCX] Stuff" +logger.tagged("BCX", "Jason") { logger.info "Stuff" } # Logs "[BCX] [Jason] Stuff" +logger.tagged("BCX") { logger.tagged("Jason") { logger.info "Stuff" } } # Logs "[BCX] [Jason] Stuff" + + h3. Debugging with the +debugger+ gem When your code is behaving in unexpected ways, you can try printing to logs or the console to diagnose the problem. Unfortunately, there are times when this sort of error tracking is not effective in finding the root cause of a problem. When you actually need to journey into your running source code, the debugger is your best companion. diff --git a/guides/source/engines.textile b/guides/source/engines.textile index fe8fcfbb3fb9c7bef50902b484b6bea97b855deb..8fcc7823f094f97dd39f5d133d147e5863be5ba9 100644 --- a/guides/source/engines.textile +++ b/guides/source/engines.textile @@ -26,7 +26,7 @@ It's important to keep in mind at all times that the application should *always* 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. There's also "Spree":https://github.com/spree/spree which provides an e-commerce platform, and "RefineryCMS":https://github.com/resolve/refinerycms, a CMS engine. -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! +Finally, engines would not have been 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 @@ -42,9 +42,9 @@ The full list of options for the plugin generator may be seen by typing: $ rails plugin --help -The +--full+ 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. +The +--full+ option tells the plugin generator that you want to create an engine, creating the basic directory structure of an engine by providing things such as an +app+ directory and a +config/routes.rb+ file. This generator also provides a file at +lib/blorgh/engine.rb+ which is identical in function to a standard Rails application's +config/application.rb+ file. -The +--mountable+ option tells the generator to mount the engine inside the dummy testing application located at +test/dummy+ inside the engine. It does this by placing this line in to the dummy application's +config/routes.rb+ file, located at +test/dummy/config/routes.rb+ inside the engine: +The +--mountable+ option tells the generator to mount the engine inside the dummy testing application located at +test/dummy+. It does this by placing this line into the dummy application's routes file at +test/dummy/config/routes.rb+: mount Blorgh::Engine, :at => "blorgh" @@ -54,7 +54,7 @@ h4. Inside an engine h5. Critical files -At the root of this brand new 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+: +At the root of this brand new engine's directory lives a +blorgh.gemspec+ file. When you include the engine into an application later on, you will do so with this line in the Rails application's +Gemfile+: gem 'blorgh', :path => "vendor/engines/blorgh" @@ -69,7 +69,7 @@ module Blorgh end -TIP: Some engines choose to use this file to put global configuration options for their engine. It's a relatively good idea, and so if you're wanting offer configuration options, the file where your engine's +module+ is defined is perfect for that. Place the methods inside the module and you'll be good to go. +TIP: Some engines choose to use this file to put global configuration options for their engine. It's a relatively good idea, and so if you want to offer configuration options, the file where your engine's +module+ is defined is perfect for that. Place the methods inside the module and you'll be good to go. Within +lib/blorgh/engine.rb+ is the base class for the engine: @@ -83,25 +83,25 @@ end By inheriting from the +Rails::Engine+ class, this gem notifies Rails that there's an engine at the specified path, and will correctly mount the engine inside the application, performing tasks such as adding the +app+ directory of the engine to the load path for models, mailers, controllers and views. -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, away from similar components inside the application. Without this, there is a possibility that the engine's components could "leak" into the application, causing unwanted disruption, or that important engine components could be overridden by similarly named things within the application. One of the examples of such conflicts are helpers. Without calling +isolate_namespace+, engine's helpers would be included in application's 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, away from similar components inside the application. Without this, there is a possibility that the engine's components could "leak" into the application, causing unwanted disruption, or that important engine components could be overridden by similarly named things within the application. One of the examples of such conflicts are helpers. Without calling +isolate_namespace+, engine's helpers would be included in an application's controllers. NOTE: It is *highly* recommended that the +isolate_namespace+ line be left within the +Engine+ class definition. Without it, classes generated in an engine *may* conflict with an application. -What this isolation of the namespace means is that a model generated by a call to +rails g model+ such as +rails g model post+ wouldn't be called +Post+, but instead be namespaced and called +Blorgh::Post+. In addition to this, the table for the model is namespaced, becoming +blorgh_posts+, rather than simply +posts+. Similar to the model namespacing, a controller called +PostsController+ would be +Blorgh::Postscontroller+ and the views for that controller would not be at +app/views/posts+, but rather +app/views/blorgh/posts+. Mailers would be namespaced as well. +What this isolation of the namespace means is that a model generated by a call to +rails g model+ such as +rails g model post+ won't be called +Post+, but instead be namespaced and called +Blorgh::Post+. In addition, the table for the model is namespaced, becoming +blorgh_posts+, rather than simply +posts+. Similar to the model namespacing, a controller called +PostsController+ becomes +Blorgh::PostsController+ and the views for that controller will not be at +app/views/posts+, but +app/views/blorgh/posts+ instead. Mailers are namespaced as well. Finally, routes will also be isolated within the engine. This is one of the most important parts about namespacing, and is discussed later in the "Routes":#routes section of this guide. h5. +app+ directory -Inside the +app+ directory there is 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, when we're writing the engine. +Inside the +app+ directory are 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, when we're writing the engine. -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/assets+ directory, there are the +images+, +javascripts+ and +stylesheets+ directories which, again, you should be familiar with due to their similarity to 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. -NOTE: The +ApplicationController+ class is called as such inside an engine -- rather than +EngineController+ -- mainly due to that if you consider that an engine is really just a mini-application, it makes sense. You should also be able to convert an application to an engine with relatively little pain, and this is just one of the ways to make that process easier, albeit however so slightly. +NOTE: The +ApplicationController+ class inside an engine is named just like a Rails application in order to make it easier for you to convert your applications into engines. -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. +Lastly, the +app/views+ directory contains a +layouts+ folder which contains a 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 application's +app/views/layouts/application.html.erb+ file. If you don't want to force a layout on to users of the engine, then you can delete this file and reference a different layout in the controllers of your engine. @@ -113,7 +113,7 @@ This directory contains one file, +script/rails+, which enables you to use the + rails g model -Keeping in mind, of course, that anything generated with these commands inside an engine that has +isolate_namespace+ inside the Engine class will be namespaced. +Keeping in mind, of course, that anything generated with these commands inside an engine that has +isolate_namespace+ inside the +Engine+ class will be namespaced. h5. +test+ directory @@ -125,13 +125,13 @@ Rails.application.routes.draw do end -This line mounts the engine at the path of +/blorgh+, which will make it accessible through the application only at that path. +This line mounts the engine at the path +/blorgh+, which will make it accessible through the application only at that path. Also in the test directory is the +test/integration+ directory, where integration tests for the engine should be placed. Other directories can be created in the +test+ directory also. For example, you may wish to create a +test/unit+ directory for your unit tests. 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. +The engine that this guide covers provides 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 @@ -189,7 +189,7 @@ end 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. This is also what causes the engine's routes to be isolated from those routes that are within the application. This is discussed further in the "Routes":#routes section of this guide. -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+). +Next, the +scaffold_controller+ generator is invoked, generating a controller 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 created is neatly namespaced. The controller's class is defined within the +Blorgh+ module: @@ -361,7 +361,7 @@ Missing partial blorgh/comments/comment with {:handlers=>[:erb, :builder], :form * "/Users/ryan/Sites/side_projects/blorgh/app/views" -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. +The engine is unable to find the partial required for rendering the comments. Rails looks first 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: @@ -375,7 +375,7 @@ That completes the comment function of the blogging engine. Now it's time to use 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. +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, 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 @@ -391,18 +391,12 @@ Usually, specifying the engine inside the Gemfile would be done by specifying it gem 'devise' -Because the +blorgh+ engine is still under development, it will need to have a +:path+ option for its +Gemfile+ specification: +However, because you are developing the +blorgh+ engine on your local machine, you will need to specify the +:path+ option in your +Gemfile+: gem 'blorgh', :path => "/path/to/blorgh" -If the whole +blorgh+ engine directory is copied to +vendor/engines/blorgh+ then it could be specified in the +Gemfile+ like this: - - -gem 'blorgh', :path => "vendor/engines/blorgh" - - 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: @@ -458,7 +452,7 @@ h5. Using a model 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. +A typical application might have a +User+ class that would be used to represent authors for a post or a comment. But there could be a case where the application calls this class something different, such as +Person+. For this reason, the engine should not hardcode associations specifically for a +User+ class. 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 inside the application: @@ -536,7 +530,7 @@ Finally, the author's name should be displayed on the post's page. Add this code

-By outputting +@post.author+ using the +<%=+ tag the +to_s+ method will be called on the object. By default, this will look quite ugly: +By outputting +@post.author+ using the +<%=+ tag, the +to_s+ method will be called on the object. By default, this will look quite ugly: # @@ -567,7 +561,7 @@ This change does require that the engine is run from a Rails application that ha 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. +This section covers how to make the +User+ class configurable, followed by general configuration tips for the engine. h5. Setting configuration settings in the application @@ -601,7 +595,7 @@ def self.user_class end -This would then turn the above code for +self.author=+ into this: +This would then turn the above code for +set_author+ into this: self.author = Blorgh.user_class.find_or_create_by_name(author_name) @@ -621,7 +615,7 @@ WARNING: It's very important here to use the +String+ version of the class, rath 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. This object, of course, should have some sort of identifier by which it can be referenced. +There are now no strict dependencies on what the class is, only what the API for the class 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. This object, of course, should have some sort of identifier by which it can be referenced. h5. General engine configuration @@ -661,11 +655,11 @@ h4. Overriding Models and Controllers Engine model and controller classes can be extended by open classing them in the main Rails application (since model and controller classes are just Ruby classes that inherit Rails specific functionality). Open classing an Engine class redefines it for use in the main applicaiton. This is usually implemented by using the decorator pattern. -For simple class modifications use Class#class_eval, and for complex class modifications, consider using ActiveSupport::Concern. +For simple class modifications use +Class#class_eval+, and for complex class modifications, consider using +ActiveSupport::Concern+. h5. Implementing Decorator Pattern Using Class#class_eval -**Adding** Post#time_since_created, +**Adding** +Post#time_since_created+, # MyApp/app/decorators/models/blorgh/post_decorator.rb @@ -681,12 +675,12 @@ end # Blorgh/app/models/post.rb class Post < ActiveRecord::Base - :has_many :comments + has_many :comments end -**Overriding** Post#summary +**Overriding** +Post#summary+ # MyApp/app/decorators/models/blorgh/post_decorator.rb @@ -702,7 +696,7 @@ end # Blorgh/app/models/post.rb class Post < ActiveRecord::Base - :has_many :comments + has_many :comments def summary "#{title}" end @@ -712,10 +706,10 @@ end h5. Implementing Decorator Pattern Using ActiveSupport::Concern -Using Class#class_eval is great for simple adjustments, but for more complex class modifications, you might want to consider using ActiveSupport::Concern. ["**ActiveSupport::Concern**":http://edgeapi.rubyonrails.org/classes/ActiveSupport/Concern.html] helps manage load order of interlinked dependencies at run time allowing you to significantly modularize your code. +Using +Class#class_eval+ is great for simple adjustments, but for more complex class modifications, you might want to consider using +ActiveSupport::Concern+. ["**ActiveSupport::Concern**":http://edgeapi.rubyonrails.org/classes/ActiveSupport/Concern.html] helps manage the load order of interlinked dependencies at run time allowing you to significantly modularize your code. -**Adding** Post#time_since_created
-**Overriding** Post#summary +**Adding** +Post#time_since_created+
+**Overriding** +Post#summary+ # MyApp/app/models/blorgh/post.rb @@ -781,7 +775,7 @@ When Rails looks for a view to render, it will first look in the +app/views+ dir 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. +You can override this view in the application by simply creating a new file at +app/views/blorgh/posts/index.html.erb+. Then 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: @@ -856,10 +850,10 @@ INFO. Remember that in order to use languages like Sass or CoffeeScript, you sho h4. Separate Assets & Precompiling -There are some situations where your engine's assets not required by the host application. For example, say that you've created +There are some situations where your engine's assets are not required by the host application. For example, say that you've created an admin functionality that only exists for your engine. In this case, the host application doesn't need to require +admin.css+ or +admin.js+. Only the gem's admin layout needs these assets. It doesn't make sense for the host app to include +"blorg/admin.css"+ in it's stylesheets. In this situation, you should explicitly define these assets for precompilation. -This tells sprockets to add you engine assets when +rake assets:precompile+ is ran. +This tells sprockets to add your engine assets when +rake assets:precompile+ is ran. You can define assets for precompilation in +engine.rb+ @@ -873,8 +867,7 @@ For more information, read the "Asset Pipeline guide":http://guides.rubyonrails. h4. Other gem dependencies -Gem dependencies inside an engine should be specified inside the +.gemspec+ file -that's at the root of the engine. The reason for this is because the engine may +Gem dependencies inside an engine should be specified inside the +.gemspec+ file at the root of the engine. The reason for this is because the engine may be installed as a gem. If dependencies were to be specified inside the +Gemfile+, these would not be recognised by a traditional gem install and so they would not be installed, causing the engine to malfunction. @@ -899,7 +892,7 @@ the application. The development dependencies for the gem will only be used when the tests for the engine are running. Note that if you want to immediately require dependencies when the engine is -required, you should require them before engine's initialization. For example: +required, you should require them before the engine's initialization. For example: require 'other_engine/engine' diff --git a/guides/source/form_helpers.textile b/guides/source/form_helpers.textile index d507a04c1ba3e3bde836d65788ae8c056a5d2e0a..d704b78f832ce370b5452eaa3b4d072a2c1b2b83 100644 --- a/guides/source/form_helpers.textile +++ b/guides/source/form_helpers.textile @@ -82,7 +82,7 @@ h4. Multiple Hashes in Form Helper Calls The +form_tag+ helper accepts 2 arguments: the path for the action and an options hash. This hash specifies the method of form submission and HTML options such as the form element's class. -As with the +link_to+ helper, the path argument doesn't have to be given a string; it can be a hash of URL parameters recognizable by Rails' routing mechanism, which will turn the hash into a valid URL. However, since both arguments to +form_tag+ are hashes, you can easily run into a problem if you would like to specify both. For instance, let's say you write this: +As with the +link_to+ helper, the path argument doesn't have to be a string; it can be a hash of URL parameters recognizable by Rails' routing mechanism, which will turn the hash into a valid URL. However, since both arguments to +form_tag+ are hashes, you can easily run into a problem if you would like to specify both. For instance, let's say you write this: form_tag(:controller => "people", :action => "search", :method => "get", :class => "nifty_form") @@ -942,4 +942,4 @@ As a convenience you can instead pass the symbol +:all_blank+ which will create h4. Adding Fields on the Fly -Rather than rendering multiple sets of fields ahead of time you may wish to add them only when a user clicks on an 'Add new child' button. Rails does not provide any builtin support for this. When generating new sets of fields you must ensure the the key of the associated array is unique - the current javascript date (milliseconds after the epoch) is a common choice. \ No newline at end of file +Rather than rendering multiple sets of fields ahead of time you may wish to add them only when a user clicks on an 'Add new child' button. Rails does not provide any builtin support for this. When generating new sets of fields you must ensure the the key of the associated array is unique - the current javascript date (milliseconds after the epoch) is a common choice. diff --git a/guides/source/i18n.textile b/guides/source/i18n.textile index 67863e590c202951173ccc844d5022c935cdf366..c073a146a842a4dd6d44ddb7bfb3026f263c5f08 100644 --- a/guides/source/i18n.textile +++ b/guides/source/i18n.textile @@ -575,11 +575,14 @@ The +:count+ interpolation variable has a special role in that it both is interp I18n.backend.store_translations :en, :inbox => { - :one => '1 message', + :one => 'one message', :other => '%{count} messages' } I18n.translate :inbox, :count => 2 # => '2 messages' + +I18n.translate :inbox, :count => 1 +# => 'one message' The algorithm for pluralizations in +:en+ is as simple as: diff --git a/guides/source/layouts_and_rendering.textile b/guides/source/layouts_and_rendering.textile index 32ceecea184d6115acb8615f4647bf13ce6ed71b..9eb8161c54b0853d5ea3c514a0e554827ec8ac2c 100644 --- a/guides/source/layouts_and_rendering.textile +++ b/guides/source/layouts_and_rendering.textile @@ -1185,7 +1185,7 @@ h5. Spacer Templates Rails will render the +_product_ruler+ partial (with no data passed in to it) between each pair of +_product+ partials. -h5. Partial Layouts +h5(#collection-partial-layouts). Partial Layouts When rendering collections it is also possible to use the +:layout+ option: diff --git a/guides/source/migrations.textile b/guides/source/migrations.textile index 587be269f7dd3e21c679b86455f36d4a27393c9c..e89bde7a83b8fb05384cbb5e7f62a837a6cad8ee 100644 --- a/guides/source/migrations.textile +++ b/guides/source/migrations.textile @@ -81,7 +81,7 @@ it to default to +false+ for new users, but existing users are considered to have already opted in, so we use the User model to set the flag to +true+ for existing users. -h4. Using the change method +h4. Using the +change+ Method Rails 3.1 makes migrations smarter by providing a new change method. This method is preferred for writing constructive migrations (adding columns or @@ -351,7 +351,7 @@ end This migration will create a user_id column and appropriate index. -h4. Supported type modifiers +h4. Supported Type Modifiers You can also specify some options just after the field type between curly braces. You can use the following modifiers: @@ -550,7 +550,7 @@ and "ActiveRecord::ConnectionAdapters::Table":http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/Table.html (which provides the methods available on the object yielded by +change_table+). -h4. Using the +change+ Method +h4. When to Use the +change+ Method The +change+ method removes the need to write both +up+ and +down+ methods in those cases that Rails knows how to revert the changes automatically. Currently, @@ -672,7 +672,7 @@ 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. -h4. Resetting the database +h4. Resetting the Database The +rake db:reset+ task will drop the database, recreate it and load the current schema into it. @@ -680,7 +680,7 @@ current schema into it. NOTE: This is not the same as running all the migrations - see the section on "schema.rb":#schema-dumping-and-you. -h4. Running specific migrations +h4. Running Specific Migrations 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 @@ -695,7 +695,7 @@ will run the +up+ method from the 20080906120000 migration. This task will first check whether the migration is already performed and will do nothing if Active Record believes that it has already been run. -h4. Changing the output of running migrations +h4. Changing the Output of Running Migrations By default migrations tell you exactly what they're doing and how long it took. A migration creating a table and adding an index might produce output like this diff --git a/guides/source/routing.textile b/guides/source/routing.textile index bed7d03e06a35116b83c2f680cf8c024c16b9924..9718887612585bd34c7b31b750b7eb63f496c423 100644 --- a/guides/source/routing.textile +++ b/guides/source/routing.textile @@ -644,10 +644,10 @@ You can also reuse dynamic segments from the match in the path to redirect to: get "/stories/:name" => redirect("/posts/%{name}") -You can also provide a block to redirect, which receives the params and (optionally) the request object: +You can also provide a block to redirect, which receives the params and the request object: -get "/stories/:name" => redirect {|params| "/posts/#{params[:name].pluralize}" } +get "/stories/:name" => redirect {|params, req| "/posts/#{params[:name].pluralize}" } get "/stories" => redirect {|p, req| "/posts/#{req.subdomain}" } diff --git a/guides/source/upgrading_ruby_on_rails.textile b/guides/source/upgrading_ruby_on_rails.textile index 70d4dabfe2a9429369dbeb928582307362be3830..b750cc2ffbd6a8407d7c81cd65092600e3969b38 100644 --- a/guides/source/upgrading_ruby_on_rails.textile +++ b/guides/source/upgrading_ruby_on_rails.textile @@ -44,7 +44,7 @@ The delete method in collection associations can now receive Fixnum Rails 4.0 has changed how orders get stacked in +ActiveRecord::Relation+. In previous versions of rails new order was applied after previous defined order. But this is no long true. Check "ActiveRecord Query guide":active_record_querying.html#ordering for more information. -Rails 4.0 has changed serialized_attributes and _attr_readonly to class methods only. Now you shouldn't use instance methods, it's deprecated. You must change them, e.g. self.serialized_attributes to self.class.serialized_attributes. +Rails 4.0 has changed serialized_attributes and _attr_readonly to class methods only. Now you shouldn't use instance methods, it's deprecated. You must change them, e.g. self.serialized_attributes to self.class.serialized_attributes. h4(#active_model4_0). Active Model