From ef2798f018d98dce28566a1679b7b85cd6acf75e Mon Sep 17 00:00:00 2001 From: rspeicher Date: Mon, 14 Jun 2010 18:11:35 -0400 Subject: Active Record Basics - Style and grammar edits - "i.e." should be "e.g." in these cases, and include the comma - Newline consistency before/after Ruby blocks - Conform to the apparent guide standard of "Active Record" over "ActiveRecord" --- .../guides/source/active_record_basics.textile | 38 ++++++++++++---------- 1 file changed, 21 insertions(+), 17 deletions(-) (limited to 'railties') diff --git a/railties/guides/source/active_record_basics.textile b/railties/guides/source/active_record_basics.textile index d81e461e63..57477b44c5 100644 --- a/railties/guides/source/active_record_basics.textile +++ b/railties/guides/source/active_record_basics.textile @@ -32,16 +32,16 @@ Active Record gives us several mechanisms, the most important being the ability * Validate models before they get persisted to the database * Perform database operations in an object-oriented fashion. -h3. Convention over Configuration in ActiveRecord +h3. Convention over Configuration in Active Record -When writing applications using other programming languages or frameworks, it may be necessary to write a lot of configuration code. This is particularly true for ORM frameworks in general. However, if you follow the conventions adopted by Rails, you'll need to write very little configuration (in some case no configuration at all) when creating ActiveRecord models. The idea is that if you configure your applications in the very same way most of the times then this should be the default way. In this cases, explicit configuration would be needed only in those cases where you can't follow the conventions for any reason. +When writing applications using other programming languages or frameworks, it may be necessary to write a lot of configuration code. This is particularly true for ORM frameworks in general. However, if you follow the conventions adopted by Rails, you'll need to write very little configuration (in some case no configuration at all) when creating Active Record models. The idea is that if you configure your applications in the very same way most of the times then this should be the default way. In this cases, explicit configuration would be needed only in those cases where you can't follow the conventions for any reason. h4. Naming Conventions -By default, ActiveRecord uses some naming conventions to find out how the mapping between models and database tables should be created. Rails will pluralize your class names to find the respective database table. So, for a class +Book+, you should have a database table called *books*. The Rails pluralization mechanisms are very powerful, being capable to pluralize (and singularize) both regular and irregular words. When using class names composed of two or more words, the model class name should follow the Ruby conventions, using the camelCase form, while the table name must contain the words separated by underscores. Examples: +By default, Active Record uses some naming conventions to find out how the mapping between models and database tables should be created. Rails will pluralize your class names to find the respective database table. So, for a class +Book+, you should have a database table called *books*. The Rails pluralization mechanisms are very powerful, being capable to pluralize (and singularize) both regular and irregular words. When using class names composed of two or more words, the model class name should follow the Ruby conventions, using the camelCase form, while the table name must contain the words separated by underscores. Examples: -* Database Table - Plural with underscores separating words i.e. (book_clubs) -* Model Class - Singular with the first letter of each word capitalized i.e. (BookClub) +* Database Table - Plural with underscores separating words (e.g., book_clubs) +* Model Class - Singular with the first letter of each word capitalized (e.g., BookClub) |_.Model / Class |_.Table / Schema | |Post |posts| @@ -53,12 +53,12 @@ By default, ActiveRecord uses some naming conventions to find out how the mappin h4. Schema Conventions -ActiveRecord uses naming conventions for the columns in database tables, depending on the purpose of these columns. +Active Record uses naming conventions for the columns in database tables, depending on the purpose of these columns. -* *Foreign keys* - These fields should be named following the pattern table_id i.e. (item_id, order_id). These are the fields that ActiveRecord will look for when you create associations between your models. -* *Primary keys* - By default, ActiveRecord will use an integer column named "id" as the table's primary key. When using "Rails Migrations":migrations.html to create your tables, this column will be automatically created. +* *Foreign keys* - These fields should be named following the pattern table_id (e.g., item_id, order_id). These are the fields that Active Record will look for when you create associations between your models. +* *Primary keys* - By default, Active Record will use an integer column named "id" as the table's primary key. When using "Rails Migrations":migrations.html to create your tables, this column will be automatically created. -There are also some optional column names that will create additional features to ActiveRecord instances: +There are also some optional column names that will create additional features to Active Record instances: * *created_at / created_on* - ActiveRecord will store the current date and time to this field when creating the record. * *updated_at / updated_on* - ActiveRecord will store the current date and times to this field when updating the record. @@ -66,17 +66,17 @@ There are also some optional column names that will create additional features t * *type* - Specifies that the model uses "Single Table Inheritance":http://api.rubyonrails.com/classes/ActiveRecord/Base.html * *(table_name)_count* - Used to cache the number of belonging objects on associations. For example, a +comments_count+ column in a +Post+ class that has many instances of +Comment+ will cache the number of existent comments for each post. -NOTE: While these column names are optional they are in fact reserved by ActiveRecord. Steer clear of reserved keywords unless you want the extra functionality. For example, "type" is a reserved keyword used to designate a table using Single Table Inheritance. If you are not using STI, try an analogous keyword like "context", that may still accurately describe the data you are modeling. +NOTE: While these column names are optional they are in fact reserved by Active Record. Steer clear of reserved keywords unless you want the extra functionality. For example, "type" is a reserved keyword used to designate a table using Single Table Inheritance. If you are not using STI, try an analogous keyword like "context", that may still accurately describe the data you are modeling. -h3. Creating ActiveRecord Models +h3. Creating Active Record Models -It's very easy to create ActiveRecord models. All you have to do is to subclass the ActiveRecord::Base class and you're good to go: +It's very easy to create Active Record models. All you have to do is to subclass the +ActiveRecord::Base+ class and you're good to go: class Product < ActiveRecord::Base; end -This will create a +Product+ model, mapped to a *products* table at the database. By doing this you'll also have the ability to map the columns of each row in that table with the attributes of the instances of your model. So, suppose that the *products* table was created using a SQL sentence like: +This will create a +Product+ model, mapped to a *products* table at the database. By doing this you'll also have the ability to map the columns of each row in that table with the attributes of the instances of your model. So, suppose that the *products* table was created using an SQL sentence like: CREATE TABLE products ( @@ -99,12 +99,15 @@ h3. Overriding the Naming Conventions What if you need to follow a different naming convention or need to use your Rails application with a legacy database? No problem, you can easily override the default conventions. You can use the +ActiveRecord::Base.set_table_name+ method to specify the table name that should be used: + class Product < ActiveRecord::Base set_table_name "PRODUCT" end + If you do so, you will have to define manually the class name that is hosting the fixtures (class_name.yml) using the +set_fixture_class+ method in your test definition: + class FunnyJoke < ActiveSupport::TestCase set_fixture_class :funny_jokes => 'Joke' @@ -113,7 +116,8 @@ class FunnyJoke < ActiveSupport::TestCase end -It's also possible to override the column that should be used as the table's primary key. Use the +ActiveRecord::Base.set_primary_key+ method for that: +It's also possible to override the column that should be used as the table's primary key using the +ActiveRecord::Base.set_primary_key+ method: + class Product < ActiveRecord::Base set_primary_key "product_id" @@ -122,7 +126,7 @@ end h3. Reading and Writing Data -CRUD is an acronym for the four verbs we use to operate on data: Create, Read, Update, Delete. Active Record automatically creates methods to allow an application to read and manipulate data stored within its tables. +CRUD is an acronym for the four verbs we use to operate on data: *C*reate, *R*ead, *U*pdate and *D*elete. Active Record automatically creates methods to allow an application to read and manipulate data stored within its tables. h4. Create @@ -155,7 +159,7 @@ Finally, passing a block to either create or new will return a new User object: h4. Read -ActiveRecord provides a rich API for accessing data within a database. Below are a few examples of different data access methods provided by ActiveRecord. +Active Record provides a rich API for accessing data within a database. Below are a few examples of different data access methods provided by Active Record. # return all records @@ -163,7 +167,7 @@ ActiveRecord provides a rich API for accessing data within a database. Below are - # return first record + # return the first record user = User.first -- cgit v1.2.3 From 6f0eb4a0984631b47f4802b29d7c611228f45b5a Mon Sep 17 00:00:00 2001 From: rspeicher Date: Mon, 14 Jun 2010 18:19:01 -0400 Subject: Active Record Basics - Separate and clarify the explanations for created_at/on and updated_at/on --- railties/guides/source/active_record_basics.textile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'railties') diff --git a/railties/guides/source/active_record_basics.textile b/railties/guides/source/active_record_basics.textile index 57477b44c5..e32898129f 100644 --- a/railties/guides/source/active_record_basics.textile +++ b/railties/guides/source/active_record_basics.textile @@ -60,8 +60,10 @@ Active Record uses naming conventions for the columns in database tables, depend There are also some optional column names that will create additional features to Active Record instances: -* *created_at / created_on* - ActiveRecord will store the current date and time to this field when creating the record. -* *updated_at / updated_on* - ActiveRecord will store the current date and times to this field when updating the record. +* *created_at* - Automatically gets set to the current date and time when the record is first created. +* *created_on* - Automatically gets set to the current date when the record is first created. +* *updated_at* - Automatically gets set to the current date and time whenever the record is updated. +* *updated_on* - Automatically gets set to the current date whenever the record is updated. * *lock_version* - Adds "optimistic locking":http://api.rubyonrails.com/classes/ActiveRecord/Locking.html to a model. * *type* - Specifies that the model uses "Single Table Inheritance":http://api.rubyonrails.com/classes/ActiveRecord/Base.html * *(table_name)_count* - Used to cache the number of belonging objects on associations. For example, a +comments_count+ column in a +Post+ class that has many instances of +Comment+ will cache the number of existent comments for each post. -- cgit v1.2.3 From 1a50cc31639f35fd82a4a24821b9fc49dc7eadc9 Mon Sep 17 00:00:00 2001 From: rspeicher Date: Mon, 14 Jun 2010 18:46:30 -0400 Subject: Routing guide - Minor typo/consistency changes --- railties/guides/source/routing.textile | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'railties') diff --git a/railties/guides/source/routing.textile b/railties/guides/source/routing.textile index 54af42a03f..3f6bb66ee5 100644 --- a/railties/guides/source/routing.textile +++ b/railties/guides/source/routing.textile @@ -32,7 +32,7 @@ the request is dispatched to the +patients+ controller's +show+ action with h4. Generating URLs from Code -You can also generate routes. If your application contains this code: +You can also generate URLs. If your application contains this code: @patient = Patient.find(17) @@ -308,7 +308,7 @@ You are not limited to the seven routes that RESTful routing creates by default. h5. Adding Member Routes -To add a member route, just add +member+ block into resource block: +To add a member route, just add a +member+ block into the resource block: resources :photos do @@ -318,9 +318,9 @@ resources :photos do end -This will recognize +/photos/1/preview+ with GET, and route to the +preview+ action of +PhotosController+. It will also create the +preview_photo_url+ and +preview_photo_path+ helpers. +This will recognize +/photos/1/preview+ with GET, and route to the +preview+ action of +PhotosController+. It will also create the +preview_photo_url+ and +preview_photo_path+ helpers. -Within the block of member routes, each route name specifies the HTTP verb that it will recognize. You can use +get+, +put+, +post+, or +delete+ here. If you don't have multiple +member+ routes, you can also passing +:on+ to a route. +Within the block of member routes, each route name specifies the HTTP verb that it will recognize. You can use +get+, +put+, +post+, or +delete+ here. If you don't have multiple +member+ routes, you can also pass +:on+ to a route, eliminating the block: resources :photos do @@ -340,9 +340,9 @@ resources :photos do end -This will enable Rails to recognize URLs such as +/photos/search+ with GET, and route to the +search+ action of +PhotosController+. It will also create the +search_photos_url+ and +search_photos_path+ route helpers. +This will enable Rails to recognize URLs such as +/photos/search+ with GET, and route to the +search+ action of +PhotosController+. It will also create the +search_photos_url+ and +search_photos_path+ route helpers. -Just as with member routes, you can pass +:on+ to a route. +Just as with member routes, you can pass +:on+ to a route: resources :photos do @@ -384,7 +384,7 @@ An incoming URL of +/photos/show/1/2+ will be dispatched to the +show+ action of h4. Static Segments -You can specify static segments when creating a route. +You can specify static segments when creating a route: match ':controller/:action/:id/with_user/:user_id' @@ -575,7 +575,7 @@ resources :photos, :constraints => {:id => /[A-Z][A-Z][0-9]+/} This declaration constrains the +:id+ parameter to match the supplied regular expression. So, in this case, the router would no longer match +/photos/1+ to this route. Instead, +/photos/RR27+ would match. -You can specify a single constraint to a apply to a number of routes by using the block form: +You can specify a single constraint to apply to a number of routes by using the block form: constraints(:id => /[A-Z][A-Z][0-9]+/) do -- cgit v1.2.3 From 33b46079bc34e19c4de66963317edafb6ff2c0b5 Mon Sep 17 00:00:00 2001 From: Bryan Woods Date: Tue, 15 Jun 2010 15:17:23 -0400 Subject: Fixing some minor typos, grammar, accuracy, and spacing issues in Active Record Validations Callbacks guide --- .../activerecord_validations_callbacks.textile | 30 +++++++++++----------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'railties') diff --git a/railties/guides/source/activerecord_validations_callbacks.textile b/railties/guides/source/activerecord_validations_callbacks.textile index 1f9bc1279a..cfd4ae55cc 100644 --- a/railties/guides/source/activerecord_validations_callbacks.textile +++ b/railties/guides/source/activerecord_validations_callbacks.textile @@ -16,7 +16,7 @@ endprologue. h3. The Object Lifecycle -During the normal operation of a Rails application objects may be created, updated, and destroyed. Active Record provides hooks into this object lifecycle so that you can control your application and its data. +During the normal operation of a Rails application, objects may be created, updated, and destroyed. Active Record provides hooks into this object lifecycle so that you can control your application and its data. Validations allow you to ensure that only valid data is stored in your database. Callbacks and observers allow you to trigger logic before or after an alteration of an object's state. @@ -71,7 +71,7 @@ The following methods trigger validations, and will save the object to the datab * +update_attributes+ * +update_attributes!+ -The bang versions (e.g. +save!+) raise an exception if the record is invalid. The non-bang versions don't: +save+ and +update_attributes+ return +false+, +create+ and +update+ just return the object/s. +The bang versions (e.g. +save!+) raise an exception if the record is invalid. The non-bang versions don't: +save+ and +update_attributes+ return +false+, +create+ and +update+ just return the objects. h4. Skipping Validations @@ -240,9 +240,9 @@ class Account < ActiveRecord::Base end -The +validates_exclusion_of+ helper has an option +:in+ that receives the set of values that will not be accepted for the validated attributes. The +:in+ option has an alias called +:within+ that you can use for the same purpose, if you'd like to. This example uses the +:message+ option to show how you can include the attribute's value. +The +validates_exclusion_of+ helper has an option +:in+ that receives the set of values that will not be accepted for the validated attributes. The +:in+ option has an alias called +:within+ that you can use for the same purpose, if you'd like to. This example uses the +:message+ option to show how you can include the attribute's value. -The default error message for +validates_exclusion_of+ is "_is reserved_". +The default error message for +validates_exclusion_of+ is "_is reserved_". h4. +validates_format_of+ @@ -270,7 +270,7 @@ end The +validates_inclusion_of+ helper has an option +:in+ that receives the set of values that will be accepted. The +:in+ option has an alias called +:within+ that you can use for the same purpose, if you'd like to. The previous example uses the +:message+ option to show how you can include the attribute's value. -The default error message for +validates_inclusion_of+ is "_is not included in the list_". +The default error message for +validates_inclusion_of+ is "_is not included in the list_". h4. +validates_length_of+ @@ -343,7 +343,7 @@ Besides +:only_integer+, the +validates_numericality_of+ helper also accepts the * +:greater_than_or_equal_to+ - Specifies the value must be greater than or equal to the supplied value. The default error message for this option is "_must be greater than or equal to %{count}_". * +:equal_to+ - Specifies the value must be equal to the supplied value. The default error message for this option is "_must be equal to %{count}_". * +:less_than+ - Specifies the value must be less than the supplied value. The default error message for this option is "_must be less than %{count}_". -* +:less_than_or_equal_to+ - Specifies the value must be less than or equal the supplied value. The default error message for this option is "_must be less or equal to %{count}_". +* +:less_than_or_equal_to+ - Specifies the value must be less than or equal the supplied value. The default error message for this option is "_must be less than or equal to %{count}_". * +:odd+ - Specifies the value must be an odd number if set to true. The default error message for this option is "_must be odd_". * +:even+ - Specifies the value must be an even number if set to true. The default error message for this option is "_must be even_". @@ -374,7 +374,7 @@ The default error message for +validates_presence_of+ is "_can't be empty_". h4. +validates_uniqueness_of+ -This helper validates that the attribute's value is unique right before the object gets saved. It does not create a uniqueness constraint in the database, so it may happen that two different database connections create two records with the same value for a column that you intend to be unique. To avoid that, you must create an unique index in your database. +This helper validates that the attribute's value is unique right before the object gets saved. It does not create a uniqueness constraint in the database, so it may happen that two different database connections create two records with the same value for a column that you intend to be unique. To avoid that, you must create a unique index in your database. class Account < ActiveRecord::Base @@ -423,14 +423,14 @@ class GoodnessValidator < ActiveRecord::Validator end -The +validates_with+ helper takes a class, or a list of classes to use for validation. There is no default error message for +validates_with+. You must manually add errors to the record's errors collection in the validator class. +The +validates_with+ helper takes a class, or a list of classes to use for validation. There is no default error message for +validates_with+. You must manually add errors to the record's errors collection in the validator class. The validator class has two attributes by default: * +record+ - the record to be validated * +options+ - the extra options that were passed to +validates_with+ -Like all other validations, +validates_with+ takes the +:if+, +:unless+ and +:on+ options. If you pass any other options, it will send those options to the validator class as +options+: +Like all other validations, +validates_with+ takes the +:if+, +:unless+ and +:on+ options. If you pass any other options, it will send those options to the validator class as +options+: class Person < ActiveRecord::Base @@ -494,7 +494,7 @@ As you've already seen, the +:message+ option lets you specify the message that h4. +:on+ -The +:on+ option lets you specify when the validation should happen. The default behavior for all the built-in validation helpers is to be ran on save (both when you're creating a new record and when you're updating it). If you want to change it, you can use +:on => :create+ to run the validation only when a new record is created or +:on => :update+ to run the validation only when a record is updated. +The +:on+ option lets you specify when the validation should happen. The default behavior for all the built-in validation helpers is to be run on save (both when you're creating a new record and when you're updating it). If you want to change it, you can use +:on => :create+ to run the validation only when a new record is created or +:on => :update+ to run the validation only when a record is updated. class Person < ActiveRecord::Base @@ -573,7 +573,7 @@ class Invoice < ActiveRecord::Base end -You can even create your own validation helpers and reuse them in several different models. For example, an application that manages surveys may find useful to express that a certain field corresponds to a set of choices: +You can even create your own validation helpers and reuse them in several different models. For example, an application that manages surveys may find it useful to express that a certain field corresponds to a set of choices: ActiveRecord::Base.class_eval do @@ -599,7 +599,7 @@ The following is a list of the most commonly used methods. Please refer to the + h4(#working_with_validation_errors-errors). +errors+ -Returns an OrderedHash with all errors. Each key is the attribute name and value is an array of strings with all errors. +Returns an OrderedHash with all errors. Each key is the attribute name and the value is an array of strings with all errors. class Person < ActiveRecord::Base @@ -619,7 +619,7 @@ person.errors # => [] h4(#working_with_validation_errors-errors-2). +errors[]+ -+errors[]+ is used when you want to check the error messages for a specific attribute. It returns an array of strings with all error messages for the given attribute, each string with one error message. If there are no errors related to the attribute returns an empty array. ++errors[]+ is used when you want to check the error messages for a specific attribute. It returns an array of strings with all error messages for the given attribute, each string with one error message. If there are no errors related to the attribute, it returns an empty array. class Person < ActiveRecord::Base @@ -681,7 +681,7 @@ Another way to do this is using +[]=+ setter h4. +errors[:base]+ -You can add errors messages that are related to the object's state as a whole, instead of being related to a specific attribute. You can use this method when you want to say that the object is invalid, no matter the values of its attributes. Since +errors[:base]+ is an array, you can simply add a string to the array and uses it as the error message. +You can add error messages that are related to the object's state as a whole, instead of being related to a specific attribute. You can use this method when you want to say that the object is invalid, no matter the values of its attributes. Since +errors[:base]+ is an array, you can simply add a string to the array and uses it as the error message. class Person < ActiveRecord::Base @@ -789,7 +789,7 @@ Both the +form.error_messages+ and the +error_messages_for+ helpers accept optio :header_tag => :h3 %> -Which results in the following content +Which results in the following content: !images/customized_error_messages.png(Customized error messages)! -- cgit v1.2.3 From f103a75b488f08dae6d3df9772bcf22b02f54777 Mon Sep 17 00:00:00 2001 From: rohit Date: Wed, 16 Jun 2010 12:48:32 +0530 Subject: Guides: AS Core Extensions, fixed a few typos. --- .../source/active_support_core_extensions.textile | 38 +++++++++++----------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'railties') diff --git a/railties/guides/source/active_support_core_extensions.textile b/railties/guides/source/active_support_core_extensions.textile index 1c17609b0a..cdd1a9ff13 100644 --- a/railties/guides/source/active_support_core_extensions.textile +++ b/railties/guides/source/active_support_core_extensions.textile @@ -159,7 +159,7 @@ NOTE: Defined in +active_support/core_ext/object/duplicable.rb+. h4. +returning+ -The method +returning+ yields its argument to a block and returns it. You tipically use it with a mutable object that gets modified in the block: +The method +returning+ yields its argument to a block and returns it. You typically use it with a mutable object that gets modified in the block: def html_options_for_form(url_for_options, options, *parameters_for_url) @@ -187,7 +187,7 @@ def log_info(sql, name, ms) end -You can shorten that using +Object#try+. This method is a synonim for +Object#send+ except that it returns +nil+ if sent to +nil+. The previous example could then be rewritten as: +You can shorten that using +Object#try+. This method is a synonym for +Object#send+ except that it returns +nil+ if sent to +nil+. The previous example could then be rewritten as: def log_info(sql, name, ms) @@ -294,7 +294,7 @@ we get: user_path(@user) # => "/users/357-john-smith" -WARNING. Controllers need to be aware of any redifinition of +to_param+ because when a request like that comes in "357-john-smith" is the value of +params[:id]+. +WARNING. Controllers need to be aware of any redefinition of +to_param+ because when a request like that comes in "357-john-smith" is the value of +params[:id]+. NOTE: Defined in +active_support/core_ext/object/to_param.rb+. @@ -332,7 +332,7 @@ Arrays return the result of applying +to_query+ to each element with _key_[] # => "sample%5B%5D=3.4&sample%5B%5D=-45.6" -Hashes also respond to +to_query+ but with a different signature. If no argument is passed a call generates a sorted series of key/value assigments calling +to_query(key)+ on its values. Then it joins the result with "&": +Hashes also respond to +to_query+ but with a different signature. If no argument is passed a call generates a sorted series of key/value assignments calling +to_query(key)+ on its values. Then it joins the result with "&": {:c => 3, :b => 2, :a => 1}.to_query # => "a=1&b=2&c=3" @@ -656,9 +656,9 @@ h5. Internal Attributes When you are defining an attribute in a class that is meant to be subclassed name collisions are a risk. That's remarkably important for libraries. -Active Support defines the macros +attr_internal_reader+, +attr_internal_writer+, and +attr_internal_accessor+. They behave like their Ruby builtin +attr_*+ counterparts, except they name the unerlying instace variable in a way that makes collisions less likely. +Active Support defines the macros +attr_internal_reader+, +attr_internal_writer+, and +attr_internal_accessor+. They behave like their Ruby builtin +attr_*+ counterparts, except they name the underlying instance variable in a way that makes collisions less likely. -The macro +attr_internal+ is a synonim for +attr_internal_accessor+: +The macro +attr_internal+ is a synonym for +attr_internal_accessor+: # library @@ -721,7 +721,7 @@ h4. Method Delegation The class method +delegate+ offers an easy way to forward methods. -For example, if +User+ has some details like the age factored out to +Profile+, it could be handy to still be able to acces such attribute directly, user.age, instead of having to explicit the chain user.profile.age. +For example, if +User+ has some details like the age factored out to +Profile+, it could be handy to still be able to access such attributes directly, user.age, instead of having to explicit the chain user.profile.age. That can be accomplished by hand: @@ -773,7 +773,7 @@ In fact, you can delegate to any expression passed as a string. It will be evalu delegate :alert, :notice, :to => "request.flash" -If the target is +nil+ calling any delegated method will raise an exception even if +nil+ responds to such method. You can override this behavior setting the option +:allow_nil+ to true, in which case the forwarded call will simply return +nil+. +If the target is +nil+ calling any delegated method will raise an exception even if +nil+ responds to such method. You can override this behaviour setting the option +:allow_nil+ to true, in which case the forwarded call will simply return +nil+. If the target is a method, the name of delegated methods can also be prefixed. If the +:prefix+ option is set to (exactly) the +true+ object, the value of the +:to+ option is prefixed: @@ -935,7 +935,7 @@ NOTE: Defined in +active_support/core_ext/module/synchronization.rb+. h4. Reachable -A named module is reachable if it is stored in its correspoding constant. It means you can reach the module object via the constant. +A named module is reachable if it is stored in its corresponding constant. It means you can reach the module object via the constant. That is what ordinarily happens, if a module is called "M", the +M+ constant exists and holds it: @@ -1016,7 +1016,7 @@ h3. Extensions to +Class+ h4. Class Attributes -The method +Class#class_attribute+ declares one or more inheritable class attributes that can be overriden at any level down the hierarchy: +The method +Class#class_attribute+ declares one or more inheritable class attributes that can be overridden at any level down the hierarchy: class A @@ -1088,7 +1088,7 @@ NOTE: Defined in +active_support/core_ext/class/attribute_accessors.rb+. h4. Class Inheritable Attributes -Class variables are shared down the inheritance tree. Class instance variables are not shared, but they are not inherited either. The macros +class_inheritable_reader+, +class_inheritable_writer+, and +class_inheritable_accessor+ provide accesors for class-level data which is inherited but not shared with children: +Class variables are shared down the inheritance tree. Class instance variables are not shared, but they are not inherited either. The macros +class_inheritable_reader+, +class_inheritable_writer+, and +class_inheritable_accessor+ provide accessors for class-level data which is inherited but not shared with children: module ActionController @@ -1204,7 +1204,7 @@ s.html_safe? # => true s # => "" -It is your responsability to ensure calling +html_safe+ on a particular string is fine. +It is your responsibility to ensure calling +html_safe+ on a particular string is fine. NOTE: For performance reasons safe strings are implemented in a way that cannot offer an in-place +html_safe!+ variant. @@ -1377,7 +1377,7 @@ The method +pluralize+ returns the plural of its receiver: "equipment".pluralize # => "equipment" -As the previous example shows, Active Support knows some irregular plurals and uncountable nouns. Builtin rules can be extended in +config/initializers/inflections.rb+. That file is generated by the +rails+ command and has instructions in comments. +As the previous example shows, Active Support knows some irregular plurals and uncountable nouns. Built-in rules can be extended in +config/initializers/inflections.rb+. That file is generated by the +rails+ command and has instructions in comments. Active Record uses this method to compute the default table name that corresponds to a model: @@ -1760,7 +1760,7 @@ h3. Extensions to +Float+ h4. +round+ -The builtin method +Float#round+ rounds a float to the nearest integer. Active Support adds an optional parameter to let you specify a precision: +The built-in method +Float#round+ rounds a float to the nearest integer. Active Support adds an optional parameter to let you specify a precision: Math::E.round(4) # => 2.7183 @@ -1925,7 +1925,7 @@ Similarly, +from+ returns the tail from the element at the passed index on: [].from(0) # => [] -The methods +second+, +third+, +fourth+, and +fifth+ return the corresponding element (+first+ is builtin). Thanks to social wisdom and positive constructiveness all around, +forty_two+ is also available. +The methods +second+, +third+, +fourth+, and +fifth+ return the corresponding element (+first+ is built-in). Thanks to social wisdom and positive constructiveness all around, +forty_two+ is also available. NOTE: Defined in +active_support/core_ext/array/access.rb+. @@ -2282,7 +2282,7 @@ NOTE: Defined in +active_support/core_ext/hash/conversions.rb+. h4. Merging -Ruby has a builtin method +Hash#merge+ that merges two hashes: +Ruby has a built-in method +Hash#merge+ that merges two hashes: {:a => 1, :b => 1}.merge(:a => 0, :c => 2) @@ -2511,7 +2511,7 @@ NOTE: Defined in +active_support/core_ext/hash/keys.rb+. h4. Slicing -Ruby has builtin support for taking slices out of strings and arrays. Active Support extends slicing to hashes: +Ruby has built-in support for taking slices out of strings and arrays. Active Support extends slicing to hashes: {:a => 1, :b => 2, :c => 3}.slice(:a, :c) @@ -2625,7 +2625,7 @@ Active Support extends this method so that the argument may be another range in (1...9).include?(3..9) # => false -WARNING: The orginal +Range#include?+ is still the one aliased to +Range#===+. +WARNING: The original +Range#include?+ is still the one aliased to +Range#===+. NOTE: Defined in +active_support/core_ext/range/include_range.rb+. @@ -2693,7 +2693,7 @@ h4. Calculations NOTE: All the following methods are defined in +active_support/core_ext/date/calculations.rb+. -INFO: The following calculation methods have edge cases in October 1582, since days 5..14 just do not exist. This guide does not document their behavior around those days for brevity, but it is enough to say that they do what you would expect. That is, +Date.new(1582, 10, 4).tomorrow+ returns +Date.new(1582, 10, 15)+ and so on. Please check +test/core_ext/date_ext_test.rb+ in the Active Support test suite for expected behavior. +INFO: The following calculation methods have edge cases in October 1582, since days 5..14 just do not exist. This guide does not document their behaviour around those days for brevity, but it is enough to say that they do what you would expect. That is, +Date.new(1582, 10, 4).tomorrow+ returns +Date.new(1582, 10, 15)+ and so on. Please check +test/core_ext/date_ext_test.rb+ in the Active Support test suite for expected behaviour. h5. +Date.current+ -- cgit v1.2.3 From 746347d997da14d6c67378518a4d7162c660212d Mon Sep 17 00:00:00 2001 From: rohit Date: Wed, 16 Jun 2010 12:52:21 +0530 Subject: Guides: AS Core Extensions, behaviour => behavior --- railties/guides/source/active_support_core_extensions.textile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'railties') diff --git a/railties/guides/source/active_support_core_extensions.textile b/railties/guides/source/active_support_core_extensions.textile index cdd1a9ff13..cd7a183def 100644 --- a/railties/guides/source/active_support_core_extensions.textile +++ b/railties/guides/source/active_support_core_extensions.textile @@ -773,7 +773,7 @@ In fact, you can delegate to any expression passed as a string. It will be evalu delegate :alert, :notice, :to => "request.flash" -If the target is +nil+ calling any delegated method will raise an exception even if +nil+ responds to such method. You can override this behaviour setting the option +:allow_nil+ to true, in which case the forwarded call will simply return +nil+. +If the target is +nil+ calling any delegated method will raise an exception even if +nil+ responds to such method. You can override this behavior setting the option +:allow_nil+ to true, in which case the forwarded call will simply return +nil+. If the target is a method, the name of delegated methods can also be prefixed. If the +:prefix+ option is set to (exactly) the +true+ object, the value of the +:to+ option is prefixed: @@ -2120,7 +2120,7 @@ NOTE: Defined in +active_support/core_ext/array/conversions.rb+. h4. Wrapping -The class method +Array.wrap+ behaves like the function +Array()+ except that it does not try to call +to_a+ on its argument. That changes the behaviour for enumerables: +The class method +Array.wrap+ behaves like the function +Array()+ except that it does not try to call +to_a+ on its argument. That changes the behavior for enumerables: Array.wrap(:foo => :bar) # => [{:foo => :bar}] @@ -2693,7 +2693,7 @@ h4. Calculations NOTE: All the following methods are defined in +active_support/core_ext/date/calculations.rb+. -INFO: The following calculation methods have edge cases in October 1582, since days 5..14 just do not exist. This guide does not document their behaviour around those days for brevity, but it is enough to say that they do what you would expect. That is, +Date.new(1582, 10, 4).tomorrow+ returns +Date.new(1582, 10, 15)+ and so on. Please check +test/core_ext/date_ext_test.rb+ in the Active Support test suite for expected behaviour. +INFO: The following calculation methods have edge cases in October 1582, since days 5..14 just do not exist. This guide does not document their behavior around those days for brevity, but it is enough to say that they do what you would expect. That is, +Date.new(1582, 10, 4).tomorrow+ returns +Date.new(1582, 10, 15)+ and so on. Please check +test/core_ext/date_ext_test.rb+ in the Active Support test suite for expected behavior. h5. +Date.current+ @@ -3080,7 +3080,7 @@ Active Support adds +missing_name?+ to +NameError+, which tests whether the exce The name may be given as a symbol or string. A symbol is tested against the bare constant name, a string is against the fully-qualified constant name. -TIP: A symbol can represent a fully-qualified constant name as in +:"ActiveRecord::Base"+, so the behaviour for symbols is defined for convenience, not because it has to be that way technically. +TIP: A symbol can represent a fully-qualified constant name as in +:"ActiveRecord::Base"+, so the behavior for symbols is defined for convenience, not because it has to be that way technically. For example, when an action of +PostsController+ is called Rails tries optimistically to use +PostsHelper+. It is OK that the helper module does not exist, so if an exception for that constant name is raised it should be silenced. But it could be the case that +posts_helper.rb+ raises a +NameError+ due to an actual unknown constant. That should be reraised. The method +missing_name?+ provides a way to distinguish both cases: -- cgit v1.2.3 From 317a75bf5860a9ab5d5535ccb4aedfabc83644d6 Mon Sep 17 00:00:00 2001 From: kaygee Date: Wed, 16 Jun 2010 12:10:50 -0500 Subject: Fix incorrect pluralization in 'These methods allows you to pass arguments...'. --- railties/guides/source/active_record_querying.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'railties') diff --git a/railties/guides/source/active_record_querying.textile b/railties/guides/source/active_record_querying.textile index 73f3ebafbe..fc07dd1267 100644 --- a/railties/guides/source/active_record_querying.textile +++ b/railties/guides/source/active_record_querying.textile @@ -51,7 +51,7 @@ Active Record will perform queries on the database for you and is compatible wit h3. Retrieving Objects from the Database -To retrieve objects from the database, Active Record provides several finder methods. These methods allows you to pass arguments into it to perform certain queries on your database without the need of writing raw SQL. +To retrieve objects from the database, Active Record provides several finder methods. These methods allow you to pass arguments into it to perform certain queries on your database without the need of writing raw SQL. The methods are: * +where+ -- cgit v1.2.3 From 9a4fc420711a7225ef0504baf97b22a3728b21a4 Mon Sep 17 00:00:00 2001 From: kaygee Date: Wed, 16 Jun 2010 13:06:46 -0500 Subject: Clarify language around list of finder methods. Clarify that finder methods return an instance of class ActiveRecord::Relation. --- railties/guides/source/active_record_querying.textile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'railties') diff --git a/railties/guides/source/active_record_querying.textile b/railties/guides/source/active_record_querying.textile index fc07dd1267..f5e70aef41 100644 --- a/railties/guides/source/active_record_querying.textile +++ b/railties/guides/source/active_record_querying.textile @@ -51,7 +51,7 @@ Active Record will perform queries on the database for you and is compatible wit h3. Retrieving Objects from the Database -To retrieve objects from the database, Active Record provides several finder methods. These methods allow you to pass arguments into it to perform certain queries on your database without the need of writing raw SQL. +To retrieve objects from the database, Active Record provides several finder methods. Each finder method allows you to pass arguments into it to perform certain queries on your database without writing raw SQL. The methods are: * +where+ @@ -66,7 +66,7 @@ The methods are: * +readonly+ * +from+ -All of these methods return a Relation +All of the above methods return an instance of ActiveRecord::Relation. Primary operation of Model.find(options) can be summarized as: -- cgit v1.2.3 From c1ff781001af157c0d5ea5ac64e1fa17d47fe1f1 Mon Sep 17 00:00:00 2001 From: Bryan Woods Date: Wed, 16 Jun 2010 15:50:32 -0400 Subject: Guides: renaming to active_record_validations_callbacks for consistency and updating links to reflect new path --- .../guides/source/active_record_basics.textile | 4 +- .../active_record_validations_callbacks.textile | 1170 ++++++++++++++++++++ .../activerecord_validations_callbacks.textile | 1170 -------------------- railties/guides/source/form_helpers.textile | 2 +- railties/guides/source/index.html.erb | 2 +- railties/guides/source/layout.html.erb | 2 +- 6 files changed, 1175 insertions(+), 1175 deletions(-) create mode 100644 railties/guides/source/active_record_validations_callbacks.textile delete mode 100644 railties/guides/source/activerecord_validations_callbacks.textile (limited to 'railties') diff --git a/railties/guides/source/active_record_basics.textile b/railties/guides/source/active_record_basics.textile index e32898129f..e6ef2cdd20 100644 --- a/railties/guides/source/active_record_basics.textile +++ b/railties/guides/source/active_record_basics.textile @@ -207,11 +207,11 @@ Likewise, once retrieved an Active Record object can be destroyed which removes h3. Validations -Active Record allows you to validate the state of a model before it gets written into the database. There are several methods that you can use to check your models and validate that an attribute value is not empty, is unique and not already in the database, follows a specific format and many more. You can learn more about validations in the "Active Record Validations and Callbacks guide":activerecord_validations_callbacks.html#validations-overview. +Active Record allows you to validate the state of a model before it gets written into the database. There are several methods that you can use to check your models and validate that an attribute value is not empty, is unique and not already in the database, follows a specific format and many more. You can learn more about validations in the "Active Record Validations and Callbacks guide":active_record_validations_callbacks.html#validations-overview. h3. Callbacks -Active Record callbacks allow you to attach code to certain events in the life-cycle of your models. This enables you to add behavior to your models by transparently executing code when those events occur, like when you create a new record, update it, destroy it and so on. You can learn more about callbacks in the "Active Record Validations and Callbacks guide":activerecord_validations_callbacks.html#callbacks-overview. +Active Record callbacks allow you to attach code to certain events in the life-cycle of your models. This enables you to add behavior to your models by transparently executing code when those events occur, like when you create a new record, update it, destroy it and so on. You can learn more about callbacks in the "Active Record Validations and Callbacks guide":active_record_validations_callbacks.html#callbacks-overview. h3. Migrations diff --git a/railties/guides/source/active_record_validations_callbacks.textile b/railties/guides/source/active_record_validations_callbacks.textile new file mode 100644 index 0000000000..cfd4ae55cc --- /dev/null +++ b/railties/guides/source/active_record_validations_callbacks.textile @@ -0,0 +1,1170 @@ +h2. Active Record Validations and Callbacks + +This guide teaches you how to hook into the lifecycle of your Active Record objects. You will learn how to validate the state of objects before they go into the database, and how to perform custom operations at certain points in the object lifecycle. + +After reading this guide and trying out the presented concepts, we hope that you'll be able to: + +* Understand the lifecycle of Active Record objects +* Use the built-in Active Record validation helpers +* Create your own custom validation methods +* Work with the error messages generated by the validation process +* Create callback methods that respond to events in the object lifecycle +* Create special classes that encapsulate common behavior for your callbacks +* Create Observers that respond to lifecycle events outside of the original class + +endprologue. + +h3. The Object Lifecycle + +During the normal operation of a Rails application, objects may be created, updated, and destroyed. Active Record provides hooks into this object lifecycle so that you can control your application and its data. + +Validations allow you to ensure that only valid data is stored in your database. Callbacks and observers allow you to trigger logic before or after an alteration of an object's state. + +h3. Validations Overview + +Before you dive into the detail of validations in Rails, you should understand a bit about how validations fit into the big picture. + +h4. Why Use Validations? + +Validations are used to ensure that only valid data is saved into your database. For example, it may be important to your application to ensure that every user provides a valid email address and mailing address. + +There are several ways to validate data before it is saved into your database, including native database constraints, client-side validations, controller-level validations, and model-level validations. + +* Database constraints and/or stored procedures make the validation mechanisms database-dependent and can make testing and maintenance more difficult. However, if your database is used by other applications, it may be a good idea to use some constraints at the database level. Additionally, database-level validations can safely handle some things (such as uniqueness in heavily-used tables) that can be difficult to implement otherwise. +* Client-side validations can be useful, but are generally unreliable if used alone. If they are implemented using JavaScript, they may be bypassed if JavaScript is turned off in the user's browser. However, if combined with other techniques, client-side validation can be a convenient way to provide users with immediate feedback as they use your site. +* Controller-level validations can be tempting to use, but often become unwieldy and difficult to test and maintain. Whenever possible, it's a good idea to "keep your controllers skinny":http://weblog.jamisbuck.org/2006/10/18/skinny-controller-fat-model, as it will make your application a pleasure to work with in the long run. +* Model-level validations are the best way to ensure that only valid data is saved into your database. They are database agnostic, cannot be bypassed by end users, and are convenient to test and maintain. Rails makes them easy to use, provides built-in helpers for common needs, and allows you to create your own validation methods as well. + +h4. When Does Validation Happen? + +There are two kinds of Active Record objects: those that correspond to a row inside your database and those that do not. When you create a fresh object, for example using the +new+ method, that object does not belong to the database yet. Once you call +save+ upon that object it will be saved into the appropriate database table. Active Record uses the +new_record?+ instance method to determine whether an object is already in the database or not. Consider the following simple Active Record class: + + +class Person < ActiveRecord::Base +end + + +We can see how it works by looking at some +rails console+ output: + + +>> p = Person.new(:name => "John Doe") +=> # +>> p.new_record? +=> true +>> p.save +=> true +>> p.new_record? +=> false + + +Creating and saving a new record will send an SQL +INSERT+ operation to the database. Updating an existing record will send an SQL +UPDATE+ operation instead. Validations are typically run before these commands are sent to the database. If any validations fail, the object will be marked as invalid and Active Record will not perform the +INSERT+ or +UPDATE+ operation. This helps to avoid storing an invalid object in the database. You can choose to have specific validations run when an object is created, saved, or updated. + +CAUTION: There are many ways to change the state of an object in the database. Some methods will trigger validations, but some will not. This means that it's possible to save an object in the database in an invalid state if you aren't careful. + +The following methods trigger validations, and will save the object to the database only if the object is valid: + +* +create+ +* +create!+ +* +save+ +* +save!+ +* +update+ +* +update_attributes+ +* +update_attributes!+ + +The bang versions (e.g. +save!+) raise an exception if the record is invalid. The non-bang versions don't: +save+ and +update_attributes+ return +false+, +create+ and +update+ just return the objects. + +h4. Skipping Validations + +The following methods skip validations, and will save the object to the database regardless of its validity. They should be used with caution. + +* +decrement!+ +* +decrement_counter+ +* +increment!+ +* +increment_counter+ +* +toggle!+ +* +update_all+ +* +update_attribute+ +* +update_counters+ + +Note that +save+ also has the ability to skip validations if passed +false+ as argument. This technique should be used with caution. + +* +save(false)+ + +h4. +valid?+ and +invalid?+ + +To verify whether or not an object is valid, Rails uses the +valid?+ method. You can also use this method on your own. +valid?+ triggers your validations and returns true if no errors were added to the object, and false otherwise. + + +class Person < ActiveRecord::Base + validates_presence_of :name +end + +Person.create(:name => "John Doe").valid? # => true +Person.create(:name => nil).valid? # => false + + +When Active Record is performing validations, any errors found can be accessed through the +errors+ instance method. By definition an object is valid if this collection is empty after running validations. + +Note that an object instantiated with +new+ will not report errors even if it's technically invalid, because validations are not run when using +new+. + + +class Person < ActiveRecord::Base + validates_presence_of :name +end + +>> p = Person.new +=> # +>> p.errors +=> {} + +>> p.valid? +=> false +>> p.errors +=> {:name=>["can't be blank"]} + +>> p = Person.create +=> # +>> p.errors +=> {:name=>["can't be blank"]} + +>> p.save +=> false + +>> p.save! +=> ActiveRecord::RecordInvalid: Validation failed: Name can't be blank + +>> Person.create! +=> ActiveRecord::RecordInvalid: Validation failed: Name can't be blank + + ++invalid?+ is simply the inverse of +valid?+. +invalid?+ triggers your validations and returns true if any errors were added to the object, and false otherwise. + +h4(#validations_overview-errors). +errors[]+ + +To verify whether or not a particular attribute of an object is valid, you can use +errors[:attribute]+ that returns an array with all attribute errors, when there are no errors on the specified attribute, an empty array is returned. + +This method is only useful _after_ validations have been run, because it only inspects the errors collection and does not trigger validations itself. It's different from the +ActiveRecord::Base#invalid?+ method explained above because it doesn't verify the validity of the object as a whole. It only checks to see whether there are errors found on an individual attribute of the object. + + +class Person < ActiveRecord::Base + validates_presence_of :name +end + +>> Person.new.errors[:name].any? # => false +>> Person.create.errors[:name].any? # => true + + +We'll cover validation errors in greater depth in the "Working with Validation Errors":#working-with-validation-errors section. For now, let's turn to the built-in validation helpers that Rails provides by default. + +h3. Validation Helpers + +Active Record offers many pre-defined validation helpers that you can use directly inside your class definitions. These helpers provide common validation rules. Every time a validation fails, an error message is added to the object's +errors+ collection, and this message is associated with the field being validated. + +Each helper accepts an arbitrary number of attribute names, so with a single line of code you can add the same kind of validation to several attributes. + +All of them accept the +:on+ and +:message+ options, which define when the validation should be run and what message should be added to the +errors+ collection if it fails, respectively. The +:on+ option takes one of the values +:save+ (the default), +:create+ or +:update+. There is a default error message for each one of the validation helpers. These messages are used when the +:message+ option isn't specified. Let's take a look at each one of the available helpers. + +h4. +validates_acceptance_of+ + +Validates that a checkbox on the user interface was checked when a form was submitted. This is typically used when the user needs to agree to your application's terms of service, confirm reading some text, or any similar concept. This validation is very specific to web applications and this 'acceptance' does not need to be recorded anywhere in your database (if you don't have a field for it, the helper will just create a virtual attribute). + + +class Person < ActiveRecord::Base + validates_acceptance_of :terms_of_service +end + + +The default error message for +validates_acceptance_of+ is "_must be accepted_". + ++validates_acceptance_of+ can receive an +:accept+ option, which determines the value that will be considered acceptance. It defaults to "1", but you can change this. + + +class Person < ActiveRecord::Base + validates_acceptance_of :terms_of_service, :accept => 'yes' +end + + +h4. +validates_associated+ + +You should use this helper when your model has associations with other models and they also need to be validated. When you try to save your object, +valid?+ will be called upon each one of the associated objects. + + +class Library < ActiveRecord::Base + has_many :books + validates_associated :books +end + + +This validation will work with all of the association types. + +CAUTION: Don't use +validates_associated+ on both ends of your associations, they would call each other in an infinite loop. + +The default error message for +validates_associated+ is "_is invalid_". Note that each associated object will contain its own +errors+ collection; errors do not bubble up to the calling model. + +h4. +validates_confirmation_of+ + +You should use this helper when you have two text fields that should receive exactly the same content. For example, you may want to confirm an email address or a password. This validation creates a virtual attribute whose name is the name of the field that has to be confirmed with "_confirmation" appended. + + +class Person < ActiveRecord::Base + validates_confirmation_of :email +end + + +In your view template you could use something like + + +<%= text_field :person, :email %> +<%= text_field :person, :email_confirmation %> + + +This check is performed only if +email_confirmation+ is not +nil+. To require confirmation, make sure to add a presence check for the confirmation attribute (we'll take a look at +validates_presence_of+ later on this guide): + + +class Person < ActiveRecord::Base + validates_confirmation_of :email + validates_presence_of :email_confirmation +end + + +The default error message for +validates_confirmation_of+ is "_doesn't match confirmation_". + +h4. +validates_exclusion_of+ + +This helper validates that the attributes' values are not included in a given set. In fact, this set can be any enumerable object. + + +class Account < ActiveRecord::Base + validates_exclusion_of :subdomain, :in => %w(www), + :message => "Subdomain %{value} is reserved." +end + + +The +validates_exclusion_of+ helper has an option +:in+ that receives the set of values that will not be accepted for the validated attributes. The +:in+ option has an alias called +:within+ that you can use for the same purpose, if you'd like to. This example uses the +:message+ option to show how you can include the attribute's value. + +The default error message for +validates_exclusion_of+ is "_is reserved_". + +h4. +validates_format_of+ + +This helper validates the attributes' values by testing whether they match a given regular expression, which is specified using the +:with+ option. + + +class Product < ActiveRecord::Base + validates_format_of :legacy_code, :with => /\A[a-zA-Z]+\z/, + :message => "Only letters allowed" +end + + +The default error message for +validates_format_of+ is "_is invalid_". + +h4. +validates_inclusion_of+ + +This helper validates that the attributes' values are included in a given set. In fact, this set can be any enumerable object. + + +class Coffee < ActiveRecord::Base + validates_inclusion_of :size, :in => %w(small medium large), + :message => "%{value} is not a valid size" +end + + +The +validates_inclusion_of+ helper has an option +:in+ that receives the set of values that will be accepted. The +:in+ option has an alias called +:within+ that you can use for the same purpose, if you'd like to. The previous example uses the +:message+ option to show how you can include the attribute's value. + +The default error message for +validates_inclusion_of+ is "_is not included in the list_". + +h4. +validates_length_of+ + +This helper validates the length of the attributes' values. It provides a variety of options, so you can specify length constraints in different ways: + + +class Person < ActiveRecord::Base + validates_length_of :name, :minimum => 2 + validates_length_of :bio, :maximum => 500 + validates_length_of :password, :in => 6..20 + validates_length_of :registration_number, :is => 6 +end + + +The possible length constraint options are: + +* +:minimum+ - The attribute cannot have less than the specified length. +* +:maximum+ - The attribute cannot have more than the specified length. +* +:in+ (or +:within+) - The attribute length must be included in a given interval. The value for this option must be a range. +* +:is+ - The attribute length must be equal to the given value. + +The default error messages depend on the type of length validation being performed. You can personalize these messages using the +:wrong_length+, +:too_long+, and +:too_short+ options and %{count} as a placeholder for the number corresponding to the length constraint being used. You can still use the +:message+ option to specify an error message. + + +class Person < ActiveRecord::Base + validates_length_of :bio, :maximum => 1000, + :too_long => "%{count} characters is the maximum allowed" +end + + +This helper counts characters by default, but you can split the value in a different way using the +:tokenizer+ option: + + +class Essay < ActiveRecord::Base + validates_length_of :content, + :minimum => 300, + :maximum => 400, + :tokenizer => lambda { |str| str.scan(/\w+/) }, + :too_short => "must have at least %{count} words", + :too_long => "must have at most %{count} words" +end + + +The +validates_size_of+ helper is an alias for +validates_length_of+. + +h4. +validates_numericality_of+ + +This helper validates that your attributes have only numeric values. By default, it will match an optional sign followed by an integral or floating point number. To specify that only integral numbers are allowed set +:only_integer+ to true. + +If you set +:only_integer+ to +true+, then it will use the + + +/\A[+-]?\d+\Z/ + + +regular expression to validate the attribute's value. Otherwise, it will try to convert the value to a number using +Float+. + +WARNING. Note that the regular expression above allows a trailing newline character. + + +class Player < ActiveRecord::Base + validates_numericality_of :points + validates_numericality_of :games_played, :only_integer => true +end + + +Besides +:only_integer+, the +validates_numericality_of+ helper also accepts the following options to add constraints to acceptable values: + +* +:greater_than+ - Specifies the value must be greater than the supplied value. The default error message for this option is "_must be greater than %{count}_". +* +:greater_than_or_equal_to+ - Specifies the value must be greater than or equal to the supplied value. The default error message for this option is "_must be greater than or equal to %{count}_". +* +:equal_to+ - Specifies the value must be equal to the supplied value. The default error message for this option is "_must be equal to %{count}_". +* +:less_than+ - Specifies the value must be less than the supplied value. The default error message for this option is "_must be less than %{count}_". +* +:less_than_or_equal_to+ - Specifies the value must be less than or equal the supplied value. The default error message for this option is "_must be less than or equal to %{count}_". +* +:odd+ - Specifies the value must be an odd number if set to true. The default error message for this option is "_must be odd_". +* +:even+ - Specifies the value must be an even number if set to true. The default error message for this option is "_must be even_". + +The default error message for +validates_numericality_of+ is "_is not a number_". + +h4. +validates_presence_of+ + +This helper validates that the specified attributes are not empty. It uses the +blank?+ method to check if the value is either +nil+ or a blank string, that is, a string that is either empty or consists of whitespace. + + +class Person < ActiveRecord::Base + validates_presence_of :name, :login, :email +end + + +If you want to be sure that an association is present, you'll need to test whether the foreign key used to map the association is present, and not the associated object itself. + + +class LineItem < ActiveRecord::Base + belongs_to :order + validates_presence_of :order_id +end + + +Since +false.blank?+ is true, if you want to validate the presence of a boolean field you should use +validates_inclusion_of :field_name, :in => [true, false]+. + +The default error message for +validates_presence_of+ is "_can't be empty_". + +h4. +validates_uniqueness_of+ + +This helper validates that the attribute's value is unique right before the object gets saved. It does not create a uniqueness constraint in the database, so it may happen that two different database connections create two records with the same value for a column that you intend to be unique. To avoid that, you must create a unique index in your database. + + +class Account < ActiveRecord::Base + validates_uniqueness_of :email +end + + +The validation happens by performing a SQL query into the model's table, searching for an existing record with the same value in that attribute. + +There is a +:scope+ option that you can use to specify other attributes that are used to limit the uniqueness check: + + +class Holiday < ActiveRecord::Base + validates_uniqueness_of :name, :scope => :year, + :message => "should happen once per year" +end + + +There is also a +:case_sensitive+ option that you can use to define whether the uniqueness constraint will be case sensitive or not. This option defaults to true. + + +class Person < ActiveRecord::Base + validates_uniqueness_of :name, :case_sensitive => false +end + + +WARNING. Note that some databases are configured to perform case-insensitive searches anyway. + +The default error message for +validates_uniqueness_of+ is "_has already been taken_". + +h4. +validates_with+ + +This helper passes the record to a separate class for validation. + + +class Person < ActiveRecord::Base + validates_with GoodnessValidator +end + +class GoodnessValidator < ActiveRecord::Validator + def validate + if record.first_name == "Evil" + record.errors[:base] << "This person is evil" + end + end +end + + +The +validates_with+ helper takes a class, or a list of classes to use for validation. There is no default error message for +validates_with+. You must manually add errors to the record's errors collection in the validator class. + +The validator class has two attributes by default: + +* +record+ - the record to be validated +* +options+ - the extra options that were passed to +validates_with+ + +Like all other validations, +validates_with+ takes the +:if+, +:unless+ and +:on+ options. If you pass any other options, it will send those options to the validator class as +options+: + + +class Person < ActiveRecord::Base + validates_with GoodnessValidator, :fields => [:first_name, :last_name] +end + +class GoodnessValidator < ActiveRecord::Validator + def validate + if options[:fields].any?{|field| record.send(field) == "Evil" } + record.errors[:base] << "This person is evil" + end + end +end + + +h4. +validates_each+ + +This helper validates attributes against a block. It doesn't have a predefined validation function. You should create one using a block, and every attribute passed to +validates_each+ will be tested against it. In the following example, we don't want names and surnames to begin with lower case. + + +class Person < ActiveRecord::Base + validates_each :name, :surname do |model, attr, value| + model.errors.add(attr, 'must start with upper case') if value =~ /\A[a-z]/ + end +end + + +The block receives the model, the attribute's name and the attribute's value. You can do anything you like to check for valid data within the block. If your validation fails, you can add an error message to the model, therefore making it invalid. + +h3. Common Validation Options + +There are some common options that all the validation helpers can use. Here they are, except for the +:if+ and +:unless+ options, which are discussed later in "Conditional Validation":#conditional-validation. + +h4. +:allow_nil+ + +The +:allow_nil+ option skips the validation when the value being validated is +nil+. Using +:allow_nil+ with +validates_presence_of+ allows for +nil+, but any other +blank?+ value will still be rejected. + + +class Coffee < ActiveRecord::Base + validates_inclusion_of :size, :in => %w(small medium large), + :message => "%{value} is not a valid size", :allow_nil => true +end + + +h4. +:allow_blank+ + +The +:allow_blank+ option is similar to the +:allow_nil+ option. This option will let validation pass if the attribute's value is +blank?+, like +nil+ or an empty string for example. + + +class Topic < ActiveRecord::Base + validates_length_of :title, :is => 5, :allow_blank => true +end + +Topic.create("title" => "").valid? # => true +Topic.create("title" => nil).valid? # => true + + +h4. +:message+ + +As you've already seen, the +:message+ option lets you specify the message that will be added to the +errors+ collection when validation fails. When this option is not used, Active Record will use the respective default error message for each validation helper. + +h4. +:on+ + +The +:on+ option lets you specify when the validation should happen. The default behavior for all the built-in validation helpers is to be run on save (both when you're creating a new record and when you're updating it). If you want to change it, you can use +:on => :create+ to run the validation only when a new record is created or +:on => :update+ to run the validation only when a record is updated. + + +class Person < ActiveRecord::Base + # it will be possible to update email with a duplicated value + validates_uniqueness_of :email, :on => :create + + # it will be possible to create the record with a non-numerical age + validates_numericality_of :age, :on => :update + + # the default (validates on both create and update) + validates_presence_of :name, :on => :save +end + + +h3. Conditional Validation + +Sometimes it will make sense to validate an object just when a given predicate is satisfied. You can do that by using the +:if+ and +:unless+ options, which can take a symbol, a string or a +Proc+. You may use the +:if+ option when you want to specify when the validation *should* happen. If you want to specify when the validation *should not* happen, then you may use the +:unless+ option. + +h4. Using a Symbol with +:if+ and +:unless+ + +You can associate the +:if+ and +:unless+ options with a symbol corresponding to the name of a method that will get called right before validation happens. This is the most commonly used option. + + +class Order < ActiveRecord::Base + validates_presence_of :card_number, :if => :paid_with_card? + + def paid_with_card? + payment_type == "card" + end +end + + +h4. Using a String with +:if+ and +:unless+ + +You can also use a string that will be evaluated using +eval+ and needs to contain valid Ruby code. You should use this option only when the string represents a really short condition. + + +class Person < ActiveRecord::Base + validates_presence_of :surname, :if => "name.nil?" +end + + +h4. Using a Proc with +:if+ and +:unless+ + +Finally, it's possible to associate +:if+ and +:unless+ with a +Proc+ object which will be called. Using a +Proc+ object gives you the ability to write an inline condition instead of a separate method. This option is best suited for one-liners. + + +class Account < ActiveRecord::Base + validates_confirmation_of :password, + :unless => Proc.new { |a| a.password.blank? } +end + + +h3. Creating Custom Validation Methods + +When the built-in validation helpers are not enough for your needs, you can write your own validation methods. + +Simply create methods that verify the state of your models and add messages to the +errors+ collection when they are invalid. You must then register these methods by using one or more of the +validate+, +validate_on_create+ or +validate_on_update+ class methods, passing in the symbols for the validation methods' names. + +You can pass more than one symbol for each class method and the respective validations will be run in the same order as they were registered. + + +class Invoice < ActiveRecord::Base + validate :expiration_date_cannot_be_in_the_past, + :discount_cannot_be_greater_than_total_value + + def expiration_date_cannot_be_in_the_past + errors.add(:expiration_date, "can't be in the past") if + !expiration_date.blank? and expiration_date < Date.today + end + + def discount_cannot_be_greater_than_total_value + errors.add(:discount, "can't be greater than total value") if + discount > total_value + end +end + + +You can even create your own validation helpers and reuse them in several different models. For example, an application that manages surveys may find it useful to express that a certain field corresponds to a set of choices: + + +ActiveRecord::Base.class_eval do + def self.validates_as_choice(attr_name, n, options={}) + validates_inclusion_of attr_name, {:in => 1..n}.merge(options) + end +end + + +Simply reopen +ActiveRecord::Base+ and define a class method like that. You'd typically put this code somewhere in +config/initializers+. You can use this helper like this: + + +class Movie < ActiveRecord::Base + validates_as_choice :rating, 5 +end + + +h3. Working with Validation Errors + +In addition to the +valid?+ and +invalid?+ methods covered earlier, Rails provides a number of methods for working with the +errors+ collection and inquiring about the validity of objects. + +The following is a list of the most commonly used methods. Please refer to the +ActiveRecord::Errors+ documentation for a list of all the available methods. + +h4(#working_with_validation_errors-errors). +errors+ + +Returns an OrderedHash with all errors. Each key is the attribute name and the value is an array of strings with all errors. + + +class Person < ActiveRecord::Base + validates_presence_of :name + validates_length_of :name, :minimum => 3 +end + +person = Person.new +person.valid? # => false +person.errors + # => {:name => ["can't be blank", "is too short (minimum is 3 characters)"]} + +person = Person.new(:name => "John Doe") +person.valid? # => true +person.errors # => [] + + +h4(#working_with_validation_errors-errors-2). +errors[]+ + ++errors[]+ is used when you want to check the error messages for a specific attribute. It returns an array of strings with all error messages for the given attribute, each string with one error message. If there are no errors related to the attribute, it returns an empty array. + + +class Person < ActiveRecord::Base + validates_presence_of :name + validates_length_of :name, :minimum => 3 +end + +person = Person.new(:name => "John Doe") +person.valid? # => true +person.errors[:name] # => [] + +person = Person.new(:name => "JD") +person.valid? # => false +person.errors[:name] # => ["is too short (minimum is 3 characters)"] + +person = Person.new +person.valid? # => false +person.errors[:name] + # => ["can't be blank", "is too short (minimum is 3 characters)"] + + +h4. +errors.add+ + +The +add+ method lets you manually add messages that are related to particular attributes. You can use the +errors.full_messages+ or +errors.to_a+ methods to view the messages in the form they might be displayed to a user. Those particular messages get the attribute name prepended (and capitalized). +add+ receives the name of the attribute you want to add the message to, and the message itself. + + +class Person < ActiveRecord::Base + def a_method_used_for_validation_purposes + errors.add(:name, "cannot contain the characters !@#%*()_-+=") + end +end + +person = Person.create(:name => "!@#") + +person.errors[:name] + # => ["cannot contain the characters !@#%*()_-+="] + +person.errors.full_messages + # => ["Name cannot contain the characters !@#%*()_-+="] + + +Another way to do this is using +[]=+ setter + + + class Person < ActiveRecord::Base + def a_method_used_for_validation_purposes + errors[:name] = "cannot contain the characters !@#%*()_-+=" + end + end + + person = Person.create(:name => "!@#") + + person.errors[:name] + # => ["cannot contain the characters !@#%*()_-+="] + + person.errors.to_a + # => ["Name cannot contain the characters !@#%*()_-+="] + + +h4. +errors[:base]+ + +You can add error messages that are related to the object's state as a whole, instead of being related to a specific attribute. You can use this method when you want to say that the object is invalid, no matter the values of its attributes. Since +errors[:base]+ is an array, you can simply add a string to the array and uses it as the error message. + + +class Person < ActiveRecord::Base + def a_method_used_for_validation_purposes + errors[:base] << "This person is invalid because ..." + end +end + + + + +h4. +errors.clear+ + +The +clear+ method is used when you intentionally want to clear all the messages in the +errors+ collection. Of course, calling +errors.clear+ upon an invalid object won't actually make it valid: the +errors+ collection will now be empty, but the next time you call +valid?+ or any method that tries to save this object to the database, the validations will run again. If any of the validations fail, the +errors+ collection will be filled again. + + +class Person < ActiveRecord::Base + validates_presence_of :name + validates_length_of :name, :minimum => 3 +end + +person = Person.new +person.valid? # => false +person.errors[:name] + # => ["can't be blank", "is too short (minimum is 3 characters)"] + +person.errors.clear +person.errors.empty? # => true + +p.save # => false + +p.errors[:name] + # => ["can't be blank", "is too short (minimum is 3 characters)"] + + +h4. +errors.size+ + +The +size+ method returns the total number of error messages for the object. + + +class Person < ActiveRecord::Base + validates_presence_of :name + validates_length_of :name, :minimum => 3 + validates_presence_of :email +end + +person = Person.new +person.valid? # => false +person.errors.size # => 3 + +person = Person.new(:name => "Andrea", :email => "andrea@example.com") +person.valid? # => true +person.errors.size # => 0 + + +h3. Displaying Validation Errors in the View + +Rails provides built-in helpers to display the error messages of your models in your view templates. + +h4. +error_messages+ and +error_messages_for+ + +When creating a form with the +form_for+ helper, you can use the +error_messages+ method on the form builder to render all failed validation messages for the current model instance. + + +class Product < ActiveRecord::Base + validates_presence_of :description, :value + validates_numericality_of :value, :allow_nil => true +end + + + +<%= form_for(@product) do |f| %> + <%= f.error_messages %> +

+ <%= f.label :description %>
+ <%= f.text_field :description %> +

+

+ <%= f.label :value %>
+ <%= f.text_field :value %> +

+

+ <%= f.submit "Create" %> +

+<% end %> +
+ +To get the idea, if you submit the form with empty fields you typically get this back, though styles are indeed missing by default: + +!images/error_messages.png(Error messages)! + +You can also use the +error_messages_for+ helper to display the error messages of a model assigned to a view template. It's very similar to the previous example and will achieve exactly the same result. + + +<%= error_messages_for :product %> + + +The displayed text for each error message will always be formed by the capitalized name of the attribute that holds the error, followed by the error message itself. + +Both the +form.error_messages+ and the +error_messages_for+ helpers accept options that let you customize the +div+ element that holds the messages, changing the header text, the message below the header text and the tag used for the element that defines the header. + + +<%= f.error_messages :header_message => "Invalid product!", + :message => "You'll need to fix the following fields:", + :header_tag => :h3 %> + + +Which results in the following content: + +!images/customized_error_messages.png(Customized error messages)! + +If you pass +nil+ to any of these options, it will get rid of the respective section of the +div+. + +h4. Customizing the Error Messages CSS + +The selectors to customize the style of error messages are: + +* +.fieldWithErrors+ - Style for the form fields and labels with errors. +* +#errorExplanation+ - Style for the +div+ element with the error messages. +* +#errorExplanation h2+ - Style for the header of the +div+ element. +* +#errorExplanation p+ - Style for the paragraph that holds the message that appears right below the header of the +div+ element. +* +#errorExplanation ul li+ - Style for the list items with individual error messages. + +Scaffolding for example generates +public/stylesheets/scaffold.css+, which defines the red-based style you saw above. + +The name of the class and the id can be changed with the +:class+ and +:id+ options, accepted by both helpers. + +h4. Customizing the Error Messages HTML + +By default, form fields with errors are displayed enclosed by a +div+ element with the +fieldWithErrors+ CSS class. However, it's possible to override that. + +The way form fields with errors are treated is defined by +ActionView::Base.field_error_proc+. This is a +Proc+ that receives two parameters: + +* A string with the HTML tag +* An instance of +ActionView::Helpers::InstanceTag+. + +Here is a simple example where we change the Rails behaviour to always display the error messages in front of each of the form fields with errors. The error messages will be enclosed by a +span+ element with a +validation-error+ CSS class. There will be no +div+ element enclosing the +input+ element, so we get rid of that red border around the text field. You can use the +validation-error+ CSS class to style it anyway you want. + + +ActionView::Base.field_error_proc = Proc.new do |html_tag, instance| + if instance.error_message.kind_of?(Array) + %(#{html_tag}  + #{instance.error_message.join(',')}) + else + %(#{html_tag}  + #{instance.error_message}) + end +end + + +This will result in something like the following: + +!images/validation_error_messages.png(Validation error messages)! + +h3. Callbacks Overview + +Callbacks are methods that get called at certain moments of an object's lifecycle. With callbacks it's possible to write code that will run whenever an Active Record object is created, saved, updated, deleted, validated, or loaded from the database. + +h4. Callback Registration + +In order to use the available callbacks, you need to register them. You can do that by implementing them as ordinary methods, and then using a macro-style class method to register them as callbacks. + + +class User < ActiveRecord::Base + validates_presence_of :login, :email + + before_validation :ensure_login_has_a_value + + protected + def ensure_login_has_a_value + if login.nil? + self.login = email unless email.blank? + end + end +end + + +The macro-style class methods can also receive a block. Consider using this style if the code inside your block is so short that it fits in just one line. + + +class User < ActiveRecord::Base + validates_presence_of :login, :email + + before_create {|user| user.name = user.login.capitalize + if user.name.blank?} +end + + +It's considered good practice to declare callback methods as being protected or private. If left public, they can be called from outside of the model and violate the principle of object encapsulation. + +h3. Available Callbacks + +Here is a list with all the available Active Record callbacks, listed in the same order in which they will get called during the respective operations: + +h4. Creating an Object + +* +before_validation+ +* +after_validation+ +* +before_save+ +* +after_save+ +* +before_create+ +* +around_create+ +* +after_create+ + +h4. Updating an Object + +* +before_validation+ +* +after_validation+ +* +before_save+ +* +after_save+ +* +before_update+ +* +around_update+ +* +after_update+ + +h4. Destroying an Object + +* +before_destroy+ +* +after_destroy+ +* +around_destroy+ + +WARNING. +after_save+ runs both on create and update, but always _after_ the more specific callbacks +after_create+ and +after_update+, no matter the order in which the macro calls were executed. + +h4. +after_initialize+ and +after_find+ + +The +after_initialize+ callback will be called whenever an Active Record object is instantiated, either by directly using +new+ or when a record is loaded from the database. It can be useful to avoid the need to directly override your Active Record +initialize+ method. + +The +after_find+ callback will be called whenever Active Record loads a record from the database. +after_find+ is called before +after_initialize+ if both are defined. + +The +after_initialize+ and +after_find+ callbacks are a bit different from the others. They have no +before_*+ counterparts, and the only way to register them is by defining them as regular methods. If you try to register +after_initialize+ or +after_find+ using macro-style class methods, they will just be ignored. This behaviour is due to performance reasons, since +after_initialize+ and +after_find+ will both be called for each record found in the database, significantly slowing down the queries. + + +class User < ActiveRecord::Base + def after_initialize + puts "You have initialized an object!" + end + + def after_find + puts "You have found an object!" + end +end + +>> User.new +You have initialized an object! +=> # + +>> User.first +You have found an object! +You have initialized an object! +=> # + + +h3. Running Callbacks + +The following methods trigger callbacks: + +* +create+ +* +create!+ +* +decrement!+ +* +destroy+ +* +destroy_all+ +* +increment!+ +* +save+ +* +save!+ +* +save(false)+ +* +toggle!+ +* +update+ +* +update_attribute+ +* +update_attributes+ +* +update_attributes!+ +* +valid?+ + +Additionally, the +after_find+ callback is triggered by the following finder methods: + +* +all+ +* +first+ +* +find+ +* +find_all_by_attribute+ +* +find_by_attribute+ +* +find_by_attribute!+ +* +last+ + +The +after_initialize+ callback is triggered every time a new object of the class is initialized. + +h3. Skipping Callbacks + +Just as with validations, it's also possible to skip callbacks. These methods should be used with caution, however, because important business rules and application logic may be kept in callbacks. Bypassing them without understanding the potential implications may lead to invalid data. + +* +decrement+ +* +decrement_counter+ +* +delete+ +* +delete_all+ +* +find_by_sql+ +* +increment+ +* +increment_counter+ +* +toggle+ +* +update_all+ +* +update_counters+ + +h3. Halting Execution + +As you start registering new callbacks for your models, they will be queued for execution. This queue will include all your model's validations, the registered callbacks, and the database operation to be executed. + +The whole callback chain is wrapped in a transaction. If any before callback method returns exactly +false+ or raises an exception the execution chain gets halted and a ROLLBACK is issued. After callbacks can only accomplish that by raising an exception. + +WARNING. Raising an arbitrary exception may break code that expects +save+ and friends not to fail like that. The +ActiveRecord::Rollback+ exception is thought precisely to tell Active Record a rollback is going on. That one is internally captured but not reraised. + +h3. Relational Callbacks + +Callbacks work through model relationships, and can even be defined by them. Let's take an example where a user has many posts. In our example, a user's posts should be destroyed if the user is destroyed. So, we'll add an +after_destroy+ callback to the +User+ model by way of its relationship to the +Post+ model. + + +class User < ActiveRecord::Base + has_many :posts, :dependent => :destroy +end + +class Post < ActiveRecord::Base + after_destroy :log_destroy_action + + def log_destroy_action + puts 'Post destroyed' + end +end + +>> user = User.first +=> # +>> user.posts.create! +=> # +>> user.destroy +Post destroyed +=> # + + +h3. Conditional Callbacks + +Like in validations, we can also make our callbacks conditional, calling them only when a given predicate is satisfied. You can do that by using the +:if+ and +:unless+ options, which can take a symbol, a string or a +Proc+. You may use the +:if+ option when you want to specify when the callback *should* get called. If you want to specify when the callback *should not* be called, then you may use the +:unless+ option. + +h4. Using +:if+ and +:unless+ with a Symbol + +You can associate the +:if+ and +:unless+ options with a symbol corresponding to the name of a method that will get called right before the callback. If this method returns +false+ the callback won't be executed. This is the most common option. Using this form of registration it's also possible to register several different methods that should be called to check if the callback should be executed. + + +class Order < ActiveRecord::Base + before_save :normalize_card_number, :if => :paid_with_card? +end + + +h4. Using +:if+ and +:unless+ with a String + +You can also use a string that will be evaluated using +eval+ and needs to contain valid Ruby code. You should use this option only when the string represents a really short condition. + + +class Order < ActiveRecord::Base + before_save :normalize_card_number, :if => "paid_with_card?" +end + + +h4. Using +:if+ and +:unless+ with a Proc + +Finally, it's possible to associate +:if+ and +:unless+ with a +Proc+ object. This option is best suited when writing short validation methods, usually one-liners. + + +class Order < ActiveRecord::Base + before_save :normalize_card_number, + :if => Proc.new { |order| order.paid_with_card? } +end + + +h4. Multiple Conditions for Callbacks + +When writing conditional callbacks, it's possible to mix both +:if+ and +:unless+ in the same callback declaration. + + +class Comment < ActiveRecord::Base + after_create :send_email_to_author, :if => :author_wants_emails?, + :unless => Proc.new { |comment| comment.post.ignore_comments? } +end + + +h3. Callback Classes + +Sometimes the callback methods that you'll write will be useful enough to be reused by other models. Active Record makes it possible to create classes that encapsulate the callback methods, so it becomes very easy to reuse them. + +Here's an example where we create a class with an +after_destroy+ callback for a +PictureFile+ model. + + +class PictureFileCallbacks + def after_destroy(picture_file) + File.delete(picture_file.filepath) + if File.exists?(picture_file.filepath) + end +end + + +When declared inside a class the callback method will receive the model object as a parameter. We can now use it this way: + + +class PictureFile < ActiveRecord::Base + after_destroy PictureFileCallbacks.new +end + + +Note that we needed to instantiate a new +PictureFileCallbacks+ object, since we declared our callback as an instance method. Sometimes it will make more sense to have it as a class method. + + +class PictureFileCallbacks + def self.after_destroy(picture_file) + File.delete(picture_file.filepath) + if File.exists?(picture_file.filepath) + end +end + + +If the callback method is declared this way, it won't be necessary to instantiate a +PictureFileCallbacks+ object. + + +class PictureFile < ActiveRecord::Base + after_destroy PictureFileCallbacks +end + + +You can declare as many callbacks as you want inside your callback classes. + +h3. Observers + +Observers are similar to callbacks, but with important differences. Whereas callbacks can pollute a model with code that isn't directly related to its purpose, observers allow you to add the same functionality outside of a model. For example, it could be argued that a +User+ model should not include code to send registration confirmation emails. Whenever you use callbacks with code that isn't directly related to your model, you may want to consider creating an observer instead. + +h4. Creating Observers + +For example, imagine a +User+ model where we want to send an email every time a new user is created. Because sending emails is not directly related to our model's purpose, we could create an observer to contain this functionality. + + +rails generate observer User + + + +class UserObserver < ActiveRecord::Observer + def after_create(model) + # code to send confirmation email... + end +end + + +As with callback classes, the observer's methods receive the observed model as a parameter. + +h4. Registering Observers + +Observers are conventionally placed inside of your +app/models+ directory and registered in your application's +config/environment.rb+ file. For example, the +UserObserver+ above would be saved as +app/models/user_observer.rb+ and registered in +config/environment.rb+ this way: + + +# Activate observers that should always be running +config.active_record.observers = :user_observer + + +As usual, settings in +config/environments+ take precedence over those in +config/environment.rb+. So, if you prefer that an observer not run in all environments, you can simply register it in a specific environment instead. + +h4. Sharing Observers + +By default, Rails will simply strip "Observer" from an observer's name to find the model it should observe. However, observers can also be used to add behaviour to more than one model, and so it's possible to manually specify the models that our observer should observe. + + +class MailerObserver < ActiveRecord::Observer + observe :registration, :user + + def after_create(model) + # code to send confirmation email... + end +end + + +In this example, the +after_create+ method would be called whenever a +Registration+ or +User+ was created. Note that this new +MailerObserver+ would also need to be registered in +config/environment.rb+ in order to take effect. + + +# Activate observers that should always be running +config.active_record.observers = :mailer_observer + + +h3. Changelog + +"Lighthouse ticket":http://rails.lighthouseapp.com/projects/16213/tickets/26-active-record-validations-and-callbacks + +* May 24, 2010: Fixed document to validate XHTML 1.0 Strict. "Jaime Iniesta":http://jaimeiniesta.com +* May 15, 2010: Validation Errors section updated by "Emili Parreño":http://www.eparreno.com +* March 7, 2009: Callbacks revision by Trevor Turk +* February 10, 2009: Observers revision by Trevor Turk +* February 5, 2009: Initial revision by Trevor Turk +* January 9, 2009: Initial version by "Cássio Marques":credits.html#cmarques diff --git a/railties/guides/source/activerecord_validations_callbacks.textile b/railties/guides/source/activerecord_validations_callbacks.textile deleted file mode 100644 index cfd4ae55cc..0000000000 --- a/railties/guides/source/activerecord_validations_callbacks.textile +++ /dev/null @@ -1,1170 +0,0 @@ -h2. Active Record Validations and Callbacks - -This guide teaches you how to hook into the lifecycle of your Active Record objects. You will learn how to validate the state of objects before they go into the database, and how to perform custom operations at certain points in the object lifecycle. - -After reading this guide and trying out the presented concepts, we hope that you'll be able to: - -* Understand the lifecycle of Active Record objects -* Use the built-in Active Record validation helpers -* Create your own custom validation methods -* Work with the error messages generated by the validation process -* Create callback methods that respond to events in the object lifecycle -* Create special classes that encapsulate common behavior for your callbacks -* Create Observers that respond to lifecycle events outside of the original class - -endprologue. - -h3. The Object Lifecycle - -During the normal operation of a Rails application, objects may be created, updated, and destroyed. Active Record provides hooks into this object lifecycle so that you can control your application and its data. - -Validations allow you to ensure that only valid data is stored in your database. Callbacks and observers allow you to trigger logic before or after an alteration of an object's state. - -h3. Validations Overview - -Before you dive into the detail of validations in Rails, you should understand a bit about how validations fit into the big picture. - -h4. Why Use Validations? - -Validations are used to ensure that only valid data is saved into your database. For example, it may be important to your application to ensure that every user provides a valid email address and mailing address. - -There are several ways to validate data before it is saved into your database, including native database constraints, client-side validations, controller-level validations, and model-level validations. - -* Database constraints and/or stored procedures make the validation mechanisms database-dependent and can make testing and maintenance more difficult. However, if your database is used by other applications, it may be a good idea to use some constraints at the database level. Additionally, database-level validations can safely handle some things (such as uniqueness in heavily-used tables) that can be difficult to implement otherwise. -* Client-side validations can be useful, but are generally unreliable if used alone. If they are implemented using JavaScript, they may be bypassed if JavaScript is turned off in the user's browser. However, if combined with other techniques, client-side validation can be a convenient way to provide users with immediate feedback as they use your site. -* Controller-level validations can be tempting to use, but often become unwieldy and difficult to test and maintain. Whenever possible, it's a good idea to "keep your controllers skinny":http://weblog.jamisbuck.org/2006/10/18/skinny-controller-fat-model, as it will make your application a pleasure to work with in the long run. -* Model-level validations are the best way to ensure that only valid data is saved into your database. They are database agnostic, cannot be bypassed by end users, and are convenient to test and maintain. Rails makes them easy to use, provides built-in helpers for common needs, and allows you to create your own validation methods as well. - -h4. When Does Validation Happen? - -There are two kinds of Active Record objects: those that correspond to a row inside your database and those that do not. When you create a fresh object, for example using the +new+ method, that object does not belong to the database yet. Once you call +save+ upon that object it will be saved into the appropriate database table. Active Record uses the +new_record?+ instance method to determine whether an object is already in the database or not. Consider the following simple Active Record class: - - -class Person < ActiveRecord::Base -end - - -We can see how it works by looking at some +rails console+ output: - - ->> p = Person.new(:name => "John Doe") -=> # ->> p.new_record? -=> true ->> p.save -=> true ->> p.new_record? -=> false - - -Creating and saving a new record will send an SQL +INSERT+ operation to the database. Updating an existing record will send an SQL +UPDATE+ operation instead. Validations are typically run before these commands are sent to the database. If any validations fail, the object will be marked as invalid and Active Record will not perform the +INSERT+ or +UPDATE+ operation. This helps to avoid storing an invalid object in the database. You can choose to have specific validations run when an object is created, saved, or updated. - -CAUTION: There are many ways to change the state of an object in the database. Some methods will trigger validations, but some will not. This means that it's possible to save an object in the database in an invalid state if you aren't careful. - -The following methods trigger validations, and will save the object to the database only if the object is valid: - -* +create+ -* +create!+ -* +save+ -* +save!+ -* +update+ -* +update_attributes+ -* +update_attributes!+ - -The bang versions (e.g. +save!+) raise an exception if the record is invalid. The non-bang versions don't: +save+ and +update_attributes+ return +false+, +create+ and +update+ just return the objects. - -h4. Skipping Validations - -The following methods skip validations, and will save the object to the database regardless of its validity. They should be used with caution. - -* +decrement!+ -* +decrement_counter+ -* +increment!+ -* +increment_counter+ -* +toggle!+ -* +update_all+ -* +update_attribute+ -* +update_counters+ - -Note that +save+ also has the ability to skip validations if passed +false+ as argument. This technique should be used with caution. - -* +save(false)+ - -h4. +valid?+ and +invalid?+ - -To verify whether or not an object is valid, Rails uses the +valid?+ method. You can also use this method on your own. +valid?+ triggers your validations and returns true if no errors were added to the object, and false otherwise. - - -class Person < ActiveRecord::Base - validates_presence_of :name -end - -Person.create(:name => "John Doe").valid? # => true -Person.create(:name => nil).valid? # => false - - -When Active Record is performing validations, any errors found can be accessed through the +errors+ instance method. By definition an object is valid if this collection is empty after running validations. - -Note that an object instantiated with +new+ will not report errors even if it's technically invalid, because validations are not run when using +new+. - - -class Person < ActiveRecord::Base - validates_presence_of :name -end - ->> p = Person.new -=> # ->> p.errors -=> {} - ->> p.valid? -=> false ->> p.errors -=> {:name=>["can't be blank"]} - ->> p = Person.create -=> # ->> p.errors -=> {:name=>["can't be blank"]} - ->> p.save -=> false - ->> p.save! -=> ActiveRecord::RecordInvalid: Validation failed: Name can't be blank - ->> Person.create! -=> ActiveRecord::RecordInvalid: Validation failed: Name can't be blank - - -+invalid?+ is simply the inverse of +valid?+. +invalid?+ triggers your validations and returns true if any errors were added to the object, and false otherwise. - -h4(#validations_overview-errors). +errors[]+ - -To verify whether or not a particular attribute of an object is valid, you can use +errors[:attribute]+ that returns an array with all attribute errors, when there are no errors on the specified attribute, an empty array is returned. - -This method is only useful _after_ validations have been run, because it only inspects the errors collection and does not trigger validations itself. It's different from the +ActiveRecord::Base#invalid?+ method explained above because it doesn't verify the validity of the object as a whole. It only checks to see whether there are errors found on an individual attribute of the object. - - -class Person < ActiveRecord::Base - validates_presence_of :name -end - ->> Person.new.errors[:name].any? # => false ->> Person.create.errors[:name].any? # => true - - -We'll cover validation errors in greater depth in the "Working with Validation Errors":#working-with-validation-errors section. For now, let's turn to the built-in validation helpers that Rails provides by default. - -h3. Validation Helpers - -Active Record offers many pre-defined validation helpers that you can use directly inside your class definitions. These helpers provide common validation rules. Every time a validation fails, an error message is added to the object's +errors+ collection, and this message is associated with the field being validated. - -Each helper accepts an arbitrary number of attribute names, so with a single line of code you can add the same kind of validation to several attributes. - -All of them accept the +:on+ and +:message+ options, which define when the validation should be run and what message should be added to the +errors+ collection if it fails, respectively. The +:on+ option takes one of the values +:save+ (the default), +:create+ or +:update+. There is a default error message for each one of the validation helpers. These messages are used when the +:message+ option isn't specified. Let's take a look at each one of the available helpers. - -h4. +validates_acceptance_of+ - -Validates that a checkbox on the user interface was checked when a form was submitted. This is typically used when the user needs to agree to your application's terms of service, confirm reading some text, or any similar concept. This validation is very specific to web applications and this 'acceptance' does not need to be recorded anywhere in your database (if you don't have a field for it, the helper will just create a virtual attribute). - - -class Person < ActiveRecord::Base - validates_acceptance_of :terms_of_service -end - - -The default error message for +validates_acceptance_of+ is "_must be accepted_". - -+validates_acceptance_of+ can receive an +:accept+ option, which determines the value that will be considered acceptance. It defaults to "1", but you can change this. - - -class Person < ActiveRecord::Base - validates_acceptance_of :terms_of_service, :accept => 'yes' -end - - -h4. +validates_associated+ - -You should use this helper when your model has associations with other models and they also need to be validated. When you try to save your object, +valid?+ will be called upon each one of the associated objects. - - -class Library < ActiveRecord::Base - has_many :books - validates_associated :books -end - - -This validation will work with all of the association types. - -CAUTION: Don't use +validates_associated+ on both ends of your associations, they would call each other in an infinite loop. - -The default error message for +validates_associated+ is "_is invalid_". Note that each associated object will contain its own +errors+ collection; errors do not bubble up to the calling model. - -h4. +validates_confirmation_of+ - -You should use this helper when you have two text fields that should receive exactly the same content. For example, you may want to confirm an email address or a password. This validation creates a virtual attribute whose name is the name of the field that has to be confirmed with "_confirmation" appended. - - -class Person < ActiveRecord::Base - validates_confirmation_of :email -end - - -In your view template you could use something like - - -<%= text_field :person, :email %> -<%= text_field :person, :email_confirmation %> - - -This check is performed only if +email_confirmation+ is not +nil+. To require confirmation, make sure to add a presence check for the confirmation attribute (we'll take a look at +validates_presence_of+ later on this guide): - - -class Person < ActiveRecord::Base - validates_confirmation_of :email - validates_presence_of :email_confirmation -end - - -The default error message for +validates_confirmation_of+ is "_doesn't match confirmation_". - -h4. +validates_exclusion_of+ - -This helper validates that the attributes' values are not included in a given set. In fact, this set can be any enumerable object. - - -class Account < ActiveRecord::Base - validates_exclusion_of :subdomain, :in => %w(www), - :message => "Subdomain %{value} is reserved." -end - - -The +validates_exclusion_of+ helper has an option +:in+ that receives the set of values that will not be accepted for the validated attributes. The +:in+ option has an alias called +:within+ that you can use for the same purpose, if you'd like to. This example uses the +:message+ option to show how you can include the attribute's value. - -The default error message for +validates_exclusion_of+ is "_is reserved_". - -h4. +validates_format_of+ - -This helper validates the attributes' values by testing whether they match a given regular expression, which is specified using the +:with+ option. - - -class Product < ActiveRecord::Base - validates_format_of :legacy_code, :with => /\A[a-zA-Z]+\z/, - :message => "Only letters allowed" -end - - -The default error message for +validates_format_of+ is "_is invalid_". - -h4. +validates_inclusion_of+ - -This helper validates that the attributes' values are included in a given set. In fact, this set can be any enumerable object. - - -class Coffee < ActiveRecord::Base - validates_inclusion_of :size, :in => %w(small medium large), - :message => "%{value} is not a valid size" -end - - -The +validates_inclusion_of+ helper has an option +:in+ that receives the set of values that will be accepted. The +:in+ option has an alias called +:within+ that you can use for the same purpose, if you'd like to. The previous example uses the +:message+ option to show how you can include the attribute's value. - -The default error message for +validates_inclusion_of+ is "_is not included in the list_". - -h4. +validates_length_of+ - -This helper validates the length of the attributes' values. It provides a variety of options, so you can specify length constraints in different ways: - - -class Person < ActiveRecord::Base - validates_length_of :name, :minimum => 2 - validates_length_of :bio, :maximum => 500 - validates_length_of :password, :in => 6..20 - validates_length_of :registration_number, :is => 6 -end - - -The possible length constraint options are: - -* +:minimum+ - The attribute cannot have less than the specified length. -* +:maximum+ - The attribute cannot have more than the specified length. -* +:in+ (or +:within+) - The attribute length must be included in a given interval. The value for this option must be a range. -* +:is+ - The attribute length must be equal to the given value. - -The default error messages depend on the type of length validation being performed. You can personalize these messages using the +:wrong_length+, +:too_long+, and +:too_short+ options and %{count} as a placeholder for the number corresponding to the length constraint being used. You can still use the +:message+ option to specify an error message. - - -class Person < ActiveRecord::Base - validates_length_of :bio, :maximum => 1000, - :too_long => "%{count} characters is the maximum allowed" -end - - -This helper counts characters by default, but you can split the value in a different way using the +:tokenizer+ option: - - -class Essay < ActiveRecord::Base - validates_length_of :content, - :minimum => 300, - :maximum => 400, - :tokenizer => lambda { |str| str.scan(/\w+/) }, - :too_short => "must have at least %{count} words", - :too_long => "must have at most %{count} words" -end - - -The +validates_size_of+ helper is an alias for +validates_length_of+. - -h4. +validates_numericality_of+ - -This helper validates that your attributes have only numeric values. By default, it will match an optional sign followed by an integral or floating point number. To specify that only integral numbers are allowed set +:only_integer+ to true. - -If you set +:only_integer+ to +true+, then it will use the - - -/\A[+-]?\d+\Z/ - - -regular expression to validate the attribute's value. Otherwise, it will try to convert the value to a number using +Float+. - -WARNING. Note that the regular expression above allows a trailing newline character. - - -class Player < ActiveRecord::Base - validates_numericality_of :points - validates_numericality_of :games_played, :only_integer => true -end - - -Besides +:only_integer+, the +validates_numericality_of+ helper also accepts the following options to add constraints to acceptable values: - -* +:greater_than+ - Specifies the value must be greater than the supplied value. The default error message for this option is "_must be greater than %{count}_". -* +:greater_than_or_equal_to+ - Specifies the value must be greater than or equal to the supplied value. The default error message for this option is "_must be greater than or equal to %{count}_". -* +:equal_to+ - Specifies the value must be equal to the supplied value. The default error message for this option is "_must be equal to %{count}_". -* +:less_than+ - Specifies the value must be less than the supplied value. The default error message for this option is "_must be less than %{count}_". -* +:less_than_or_equal_to+ - Specifies the value must be less than or equal the supplied value. The default error message for this option is "_must be less than or equal to %{count}_". -* +:odd+ - Specifies the value must be an odd number if set to true. The default error message for this option is "_must be odd_". -* +:even+ - Specifies the value must be an even number if set to true. The default error message for this option is "_must be even_". - -The default error message for +validates_numericality_of+ is "_is not a number_". - -h4. +validates_presence_of+ - -This helper validates that the specified attributes are not empty. It uses the +blank?+ method to check if the value is either +nil+ or a blank string, that is, a string that is either empty or consists of whitespace. - - -class Person < ActiveRecord::Base - validates_presence_of :name, :login, :email -end - - -If you want to be sure that an association is present, you'll need to test whether the foreign key used to map the association is present, and not the associated object itself. - - -class LineItem < ActiveRecord::Base - belongs_to :order - validates_presence_of :order_id -end - - -Since +false.blank?+ is true, if you want to validate the presence of a boolean field you should use +validates_inclusion_of :field_name, :in => [true, false]+. - -The default error message for +validates_presence_of+ is "_can't be empty_". - -h4. +validates_uniqueness_of+ - -This helper validates that the attribute's value is unique right before the object gets saved. It does not create a uniqueness constraint in the database, so it may happen that two different database connections create two records with the same value for a column that you intend to be unique. To avoid that, you must create a unique index in your database. - - -class Account < ActiveRecord::Base - validates_uniqueness_of :email -end - - -The validation happens by performing a SQL query into the model's table, searching for an existing record with the same value in that attribute. - -There is a +:scope+ option that you can use to specify other attributes that are used to limit the uniqueness check: - - -class Holiday < ActiveRecord::Base - validates_uniqueness_of :name, :scope => :year, - :message => "should happen once per year" -end - - -There is also a +:case_sensitive+ option that you can use to define whether the uniqueness constraint will be case sensitive or not. This option defaults to true. - - -class Person < ActiveRecord::Base - validates_uniqueness_of :name, :case_sensitive => false -end - - -WARNING. Note that some databases are configured to perform case-insensitive searches anyway. - -The default error message for +validates_uniqueness_of+ is "_has already been taken_". - -h4. +validates_with+ - -This helper passes the record to a separate class for validation. - - -class Person < ActiveRecord::Base - validates_with GoodnessValidator -end - -class GoodnessValidator < ActiveRecord::Validator - def validate - if record.first_name == "Evil" - record.errors[:base] << "This person is evil" - end - end -end - - -The +validates_with+ helper takes a class, or a list of classes to use for validation. There is no default error message for +validates_with+. You must manually add errors to the record's errors collection in the validator class. - -The validator class has two attributes by default: - -* +record+ - the record to be validated -* +options+ - the extra options that were passed to +validates_with+ - -Like all other validations, +validates_with+ takes the +:if+, +:unless+ and +:on+ options. If you pass any other options, it will send those options to the validator class as +options+: - - -class Person < ActiveRecord::Base - validates_with GoodnessValidator, :fields => [:first_name, :last_name] -end - -class GoodnessValidator < ActiveRecord::Validator - def validate - if options[:fields].any?{|field| record.send(field) == "Evil" } - record.errors[:base] << "This person is evil" - end - end -end - - -h4. +validates_each+ - -This helper validates attributes against a block. It doesn't have a predefined validation function. You should create one using a block, and every attribute passed to +validates_each+ will be tested against it. In the following example, we don't want names and surnames to begin with lower case. - - -class Person < ActiveRecord::Base - validates_each :name, :surname do |model, attr, value| - model.errors.add(attr, 'must start with upper case') if value =~ /\A[a-z]/ - end -end - - -The block receives the model, the attribute's name and the attribute's value. You can do anything you like to check for valid data within the block. If your validation fails, you can add an error message to the model, therefore making it invalid. - -h3. Common Validation Options - -There are some common options that all the validation helpers can use. Here they are, except for the +:if+ and +:unless+ options, which are discussed later in "Conditional Validation":#conditional-validation. - -h4. +:allow_nil+ - -The +:allow_nil+ option skips the validation when the value being validated is +nil+. Using +:allow_nil+ with +validates_presence_of+ allows for +nil+, but any other +blank?+ value will still be rejected. - - -class Coffee < ActiveRecord::Base - validates_inclusion_of :size, :in => %w(small medium large), - :message => "%{value} is not a valid size", :allow_nil => true -end - - -h4. +:allow_blank+ - -The +:allow_blank+ option is similar to the +:allow_nil+ option. This option will let validation pass if the attribute's value is +blank?+, like +nil+ or an empty string for example. - - -class Topic < ActiveRecord::Base - validates_length_of :title, :is => 5, :allow_blank => true -end - -Topic.create("title" => "").valid? # => true -Topic.create("title" => nil).valid? # => true - - -h4. +:message+ - -As you've already seen, the +:message+ option lets you specify the message that will be added to the +errors+ collection when validation fails. When this option is not used, Active Record will use the respective default error message for each validation helper. - -h4. +:on+ - -The +:on+ option lets you specify when the validation should happen. The default behavior for all the built-in validation helpers is to be run on save (both when you're creating a new record and when you're updating it). If you want to change it, you can use +:on => :create+ to run the validation only when a new record is created or +:on => :update+ to run the validation only when a record is updated. - - -class Person < ActiveRecord::Base - # it will be possible to update email with a duplicated value - validates_uniqueness_of :email, :on => :create - - # it will be possible to create the record with a non-numerical age - validates_numericality_of :age, :on => :update - - # the default (validates on both create and update) - validates_presence_of :name, :on => :save -end - - -h3. Conditional Validation - -Sometimes it will make sense to validate an object just when a given predicate is satisfied. You can do that by using the +:if+ and +:unless+ options, which can take a symbol, a string or a +Proc+. You may use the +:if+ option when you want to specify when the validation *should* happen. If you want to specify when the validation *should not* happen, then you may use the +:unless+ option. - -h4. Using a Symbol with +:if+ and +:unless+ - -You can associate the +:if+ and +:unless+ options with a symbol corresponding to the name of a method that will get called right before validation happens. This is the most commonly used option. - - -class Order < ActiveRecord::Base - validates_presence_of :card_number, :if => :paid_with_card? - - def paid_with_card? - payment_type == "card" - end -end - - -h4. Using a String with +:if+ and +:unless+ - -You can also use a string that will be evaluated using +eval+ and needs to contain valid Ruby code. You should use this option only when the string represents a really short condition. - - -class Person < ActiveRecord::Base - validates_presence_of :surname, :if => "name.nil?" -end - - -h4. Using a Proc with +:if+ and +:unless+ - -Finally, it's possible to associate +:if+ and +:unless+ with a +Proc+ object which will be called. Using a +Proc+ object gives you the ability to write an inline condition instead of a separate method. This option is best suited for one-liners. - - -class Account < ActiveRecord::Base - validates_confirmation_of :password, - :unless => Proc.new { |a| a.password.blank? } -end - - -h3. Creating Custom Validation Methods - -When the built-in validation helpers are not enough for your needs, you can write your own validation methods. - -Simply create methods that verify the state of your models and add messages to the +errors+ collection when they are invalid. You must then register these methods by using one or more of the +validate+, +validate_on_create+ or +validate_on_update+ class methods, passing in the symbols for the validation methods' names. - -You can pass more than one symbol for each class method and the respective validations will be run in the same order as they were registered. - - -class Invoice < ActiveRecord::Base - validate :expiration_date_cannot_be_in_the_past, - :discount_cannot_be_greater_than_total_value - - def expiration_date_cannot_be_in_the_past - errors.add(:expiration_date, "can't be in the past") if - !expiration_date.blank? and expiration_date < Date.today - end - - def discount_cannot_be_greater_than_total_value - errors.add(:discount, "can't be greater than total value") if - discount > total_value - end -end - - -You can even create your own validation helpers and reuse them in several different models. For example, an application that manages surveys may find it useful to express that a certain field corresponds to a set of choices: - - -ActiveRecord::Base.class_eval do - def self.validates_as_choice(attr_name, n, options={}) - validates_inclusion_of attr_name, {:in => 1..n}.merge(options) - end -end - - -Simply reopen +ActiveRecord::Base+ and define a class method like that. You'd typically put this code somewhere in +config/initializers+. You can use this helper like this: - - -class Movie < ActiveRecord::Base - validates_as_choice :rating, 5 -end - - -h3. Working with Validation Errors - -In addition to the +valid?+ and +invalid?+ methods covered earlier, Rails provides a number of methods for working with the +errors+ collection and inquiring about the validity of objects. - -The following is a list of the most commonly used methods. Please refer to the +ActiveRecord::Errors+ documentation for a list of all the available methods. - -h4(#working_with_validation_errors-errors). +errors+ - -Returns an OrderedHash with all errors. Each key is the attribute name and the value is an array of strings with all errors. - - -class Person < ActiveRecord::Base - validates_presence_of :name - validates_length_of :name, :minimum => 3 -end - -person = Person.new -person.valid? # => false -person.errors - # => {:name => ["can't be blank", "is too short (minimum is 3 characters)"]} - -person = Person.new(:name => "John Doe") -person.valid? # => true -person.errors # => [] - - -h4(#working_with_validation_errors-errors-2). +errors[]+ - -+errors[]+ is used when you want to check the error messages for a specific attribute. It returns an array of strings with all error messages for the given attribute, each string with one error message. If there are no errors related to the attribute, it returns an empty array. - - -class Person < ActiveRecord::Base - validates_presence_of :name - validates_length_of :name, :minimum => 3 -end - -person = Person.new(:name => "John Doe") -person.valid? # => true -person.errors[:name] # => [] - -person = Person.new(:name => "JD") -person.valid? # => false -person.errors[:name] # => ["is too short (minimum is 3 characters)"] - -person = Person.new -person.valid? # => false -person.errors[:name] - # => ["can't be blank", "is too short (minimum is 3 characters)"] - - -h4. +errors.add+ - -The +add+ method lets you manually add messages that are related to particular attributes. You can use the +errors.full_messages+ or +errors.to_a+ methods to view the messages in the form they might be displayed to a user. Those particular messages get the attribute name prepended (and capitalized). +add+ receives the name of the attribute you want to add the message to, and the message itself. - - -class Person < ActiveRecord::Base - def a_method_used_for_validation_purposes - errors.add(:name, "cannot contain the characters !@#%*()_-+=") - end -end - -person = Person.create(:name => "!@#") - -person.errors[:name] - # => ["cannot contain the characters !@#%*()_-+="] - -person.errors.full_messages - # => ["Name cannot contain the characters !@#%*()_-+="] - - -Another way to do this is using +[]=+ setter - - - class Person < ActiveRecord::Base - def a_method_used_for_validation_purposes - errors[:name] = "cannot contain the characters !@#%*()_-+=" - end - end - - person = Person.create(:name => "!@#") - - person.errors[:name] - # => ["cannot contain the characters !@#%*()_-+="] - - person.errors.to_a - # => ["Name cannot contain the characters !@#%*()_-+="] - - -h4. +errors[:base]+ - -You can add error messages that are related to the object's state as a whole, instead of being related to a specific attribute. You can use this method when you want to say that the object is invalid, no matter the values of its attributes. Since +errors[:base]+ is an array, you can simply add a string to the array and uses it as the error message. - - -class Person < ActiveRecord::Base - def a_method_used_for_validation_purposes - errors[:base] << "This person is invalid because ..." - end -end - - - - -h4. +errors.clear+ - -The +clear+ method is used when you intentionally want to clear all the messages in the +errors+ collection. Of course, calling +errors.clear+ upon an invalid object won't actually make it valid: the +errors+ collection will now be empty, but the next time you call +valid?+ or any method that tries to save this object to the database, the validations will run again. If any of the validations fail, the +errors+ collection will be filled again. - - -class Person < ActiveRecord::Base - validates_presence_of :name - validates_length_of :name, :minimum => 3 -end - -person = Person.new -person.valid? # => false -person.errors[:name] - # => ["can't be blank", "is too short (minimum is 3 characters)"] - -person.errors.clear -person.errors.empty? # => true - -p.save # => false - -p.errors[:name] - # => ["can't be blank", "is too short (minimum is 3 characters)"] - - -h4. +errors.size+ - -The +size+ method returns the total number of error messages for the object. - - -class Person < ActiveRecord::Base - validates_presence_of :name - validates_length_of :name, :minimum => 3 - validates_presence_of :email -end - -person = Person.new -person.valid? # => false -person.errors.size # => 3 - -person = Person.new(:name => "Andrea", :email => "andrea@example.com") -person.valid? # => true -person.errors.size # => 0 - - -h3. Displaying Validation Errors in the View - -Rails provides built-in helpers to display the error messages of your models in your view templates. - -h4. +error_messages+ and +error_messages_for+ - -When creating a form with the +form_for+ helper, you can use the +error_messages+ method on the form builder to render all failed validation messages for the current model instance. - - -class Product < ActiveRecord::Base - validates_presence_of :description, :value - validates_numericality_of :value, :allow_nil => true -end - - - -<%= form_for(@product) do |f| %> - <%= f.error_messages %> -

- <%= f.label :description %>
- <%= f.text_field :description %> -

-

- <%= f.label :value %>
- <%= f.text_field :value %> -

-

- <%= f.submit "Create" %> -

-<% end %> -
- -To get the idea, if you submit the form with empty fields you typically get this back, though styles are indeed missing by default: - -!images/error_messages.png(Error messages)! - -You can also use the +error_messages_for+ helper to display the error messages of a model assigned to a view template. It's very similar to the previous example and will achieve exactly the same result. - - -<%= error_messages_for :product %> - - -The displayed text for each error message will always be formed by the capitalized name of the attribute that holds the error, followed by the error message itself. - -Both the +form.error_messages+ and the +error_messages_for+ helpers accept options that let you customize the +div+ element that holds the messages, changing the header text, the message below the header text and the tag used for the element that defines the header. - - -<%= f.error_messages :header_message => "Invalid product!", - :message => "You'll need to fix the following fields:", - :header_tag => :h3 %> - - -Which results in the following content: - -!images/customized_error_messages.png(Customized error messages)! - -If you pass +nil+ to any of these options, it will get rid of the respective section of the +div+. - -h4. Customizing the Error Messages CSS - -The selectors to customize the style of error messages are: - -* +.fieldWithErrors+ - Style for the form fields and labels with errors. -* +#errorExplanation+ - Style for the +div+ element with the error messages. -* +#errorExplanation h2+ - Style for the header of the +div+ element. -* +#errorExplanation p+ - Style for the paragraph that holds the message that appears right below the header of the +div+ element. -* +#errorExplanation ul li+ - Style for the list items with individual error messages. - -Scaffolding for example generates +public/stylesheets/scaffold.css+, which defines the red-based style you saw above. - -The name of the class and the id can be changed with the +:class+ and +:id+ options, accepted by both helpers. - -h4. Customizing the Error Messages HTML - -By default, form fields with errors are displayed enclosed by a +div+ element with the +fieldWithErrors+ CSS class. However, it's possible to override that. - -The way form fields with errors are treated is defined by +ActionView::Base.field_error_proc+. This is a +Proc+ that receives two parameters: - -* A string with the HTML tag -* An instance of +ActionView::Helpers::InstanceTag+. - -Here is a simple example where we change the Rails behaviour to always display the error messages in front of each of the form fields with errors. The error messages will be enclosed by a +span+ element with a +validation-error+ CSS class. There will be no +div+ element enclosing the +input+ element, so we get rid of that red border around the text field. You can use the +validation-error+ CSS class to style it anyway you want. - - -ActionView::Base.field_error_proc = Proc.new do |html_tag, instance| - if instance.error_message.kind_of?(Array) - %(#{html_tag}  - #{instance.error_message.join(',')}) - else - %(#{html_tag}  - #{instance.error_message}) - end -end - - -This will result in something like the following: - -!images/validation_error_messages.png(Validation error messages)! - -h3. Callbacks Overview - -Callbacks are methods that get called at certain moments of an object's lifecycle. With callbacks it's possible to write code that will run whenever an Active Record object is created, saved, updated, deleted, validated, or loaded from the database. - -h4. Callback Registration - -In order to use the available callbacks, you need to register them. You can do that by implementing them as ordinary methods, and then using a macro-style class method to register them as callbacks. - - -class User < ActiveRecord::Base - validates_presence_of :login, :email - - before_validation :ensure_login_has_a_value - - protected - def ensure_login_has_a_value - if login.nil? - self.login = email unless email.blank? - end - end -end - - -The macro-style class methods can also receive a block. Consider using this style if the code inside your block is so short that it fits in just one line. - - -class User < ActiveRecord::Base - validates_presence_of :login, :email - - before_create {|user| user.name = user.login.capitalize - if user.name.blank?} -end - - -It's considered good practice to declare callback methods as being protected or private. If left public, they can be called from outside of the model and violate the principle of object encapsulation. - -h3. Available Callbacks - -Here is a list with all the available Active Record callbacks, listed in the same order in which they will get called during the respective operations: - -h4. Creating an Object - -* +before_validation+ -* +after_validation+ -* +before_save+ -* +after_save+ -* +before_create+ -* +around_create+ -* +after_create+ - -h4. Updating an Object - -* +before_validation+ -* +after_validation+ -* +before_save+ -* +after_save+ -* +before_update+ -* +around_update+ -* +after_update+ - -h4. Destroying an Object - -* +before_destroy+ -* +after_destroy+ -* +around_destroy+ - -WARNING. +after_save+ runs both on create and update, but always _after_ the more specific callbacks +after_create+ and +after_update+, no matter the order in which the macro calls were executed. - -h4. +after_initialize+ and +after_find+ - -The +after_initialize+ callback will be called whenever an Active Record object is instantiated, either by directly using +new+ or when a record is loaded from the database. It can be useful to avoid the need to directly override your Active Record +initialize+ method. - -The +after_find+ callback will be called whenever Active Record loads a record from the database. +after_find+ is called before +after_initialize+ if both are defined. - -The +after_initialize+ and +after_find+ callbacks are a bit different from the others. They have no +before_*+ counterparts, and the only way to register them is by defining them as regular methods. If you try to register +after_initialize+ or +after_find+ using macro-style class methods, they will just be ignored. This behaviour is due to performance reasons, since +after_initialize+ and +after_find+ will both be called for each record found in the database, significantly slowing down the queries. - - -class User < ActiveRecord::Base - def after_initialize - puts "You have initialized an object!" - end - - def after_find - puts "You have found an object!" - end -end - ->> User.new -You have initialized an object! -=> # - ->> User.first -You have found an object! -You have initialized an object! -=> # - - -h3. Running Callbacks - -The following methods trigger callbacks: - -* +create+ -* +create!+ -* +decrement!+ -* +destroy+ -* +destroy_all+ -* +increment!+ -* +save+ -* +save!+ -* +save(false)+ -* +toggle!+ -* +update+ -* +update_attribute+ -* +update_attributes+ -* +update_attributes!+ -* +valid?+ - -Additionally, the +after_find+ callback is triggered by the following finder methods: - -* +all+ -* +first+ -* +find+ -* +find_all_by_attribute+ -* +find_by_attribute+ -* +find_by_attribute!+ -* +last+ - -The +after_initialize+ callback is triggered every time a new object of the class is initialized. - -h3. Skipping Callbacks - -Just as with validations, it's also possible to skip callbacks. These methods should be used with caution, however, because important business rules and application logic may be kept in callbacks. Bypassing them without understanding the potential implications may lead to invalid data. - -* +decrement+ -* +decrement_counter+ -* +delete+ -* +delete_all+ -* +find_by_sql+ -* +increment+ -* +increment_counter+ -* +toggle+ -* +update_all+ -* +update_counters+ - -h3. Halting Execution - -As you start registering new callbacks for your models, they will be queued for execution. This queue will include all your model's validations, the registered callbacks, and the database operation to be executed. - -The whole callback chain is wrapped in a transaction. If any before callback method returns exactly +false+ or raises an exception the execution chain gets halted and a ROLLBACK is issued. After callbacks can only accomplish that by raising an exception. - -WARNING. Raising an arbitrary exception may break code that expects +save+ and friends not to fail like that. The +ActiveRecord::Rollback+ exception is thought precisely to tell Active Record a rollback is going on. That one is internally captured but not reraised. - -h3. Relational Callbacks - -Callbacks work through model relationships, and can even be defined by them. Let's take an example where a user has many posts. In our example, a user's posts should be destroyed if the user is destroyed. So, we'll add an +after_destroy+ callback to the +User+ model by way of its relationship to the +Post+ model. - - -class User < ActiveRecord::Base - has_many :posts, :dependent => :destroy -end - -class Post < ActiveRecord::Base - after_destroy :log_destroy_action - - def log_destroy_action - puts 'Post destroyed' - end -end - ->> user = User.first -=> # ->> user.posts.create! -=> # ->> user.destroy -Post destroyed -=> # - - -h3. Conditional Callbacks - -Like in validations, we can also make our callbacks conditional, calling them only when a given predicate is satisfied. You can do that by using the +:if+ and +:unless+ options, which can take a symbol, a string or a +Proc+. You may use the +:if+ option when you want to specify when the callback *should* get called. If you want to specify when the callback *should not* be called, then you may use the +:unless+ option. - -h4. Using +:if+ and +:unless+ with a Symbol - -You can associate the +:if+ and +:unless+ options with a symbol corresponding to the name of a method that will get called right before the callback. If this method returns +false+ the callback won't be executed. This is the most common option. Using this form of registration it's also possible to register several different methods that should be called to check if the callback should be executed. - - -class Order < ActiveRecord::Base - before_save :normalize_card_number, :if => :paid_with_card? -end - - -h4. Using +:if+ and +:unless+ with a String - -You can also use a string that will be evaluated using +eval+ and needs to contain valid Ruby code. You should use this option only when the string represents a really short condition. - - -class Order < ActiveRecord::Base - before_save :normalize_card_number, :if => "paid_with_card?" -end - - -h4. Using +:if+ and +:unless+ with a Proc - -Finally, it's possible to associate +:if+ and +:unless+ with a +Proc+ object. This option is best suited when writing short validation methods, usually one-liners. - - -class Order < ActiveRecord::Base - before_save :normalize_card_number, - :if => Proc.new { |order| order.paid_with_card? } -end - - -h4. Multiple Conditions for Callbacks - -When writing conditional callbacks, it's possible to mix both +:if+ and +:unless+ in the same callback declaration. - - -class Comment < ActiveRecord::Base - after_create :send_email_to_author, :if => :author_wants_emails?, - :unless => Proc.new { |comment| comment.post.ignore_comments? } -end - - -h3. Callback Classes - -Sometimes the callback methods that you'll write will be useful enough to be reused by other models. Active Record makes it possible to create classes that encapsulate the callback methods, so it becomes very easy to reuse them. - -Here's an example where we create a class with an +after_destroy+ callback for a +PictureFile+ model. - - -class PictureFileCallbacks - def after_destroy(picture_file) - File.delete(picture_file.filepath) - if File.exists?(picture_file.filepath) - end -end - - -When declared inside a class the callback method will receive the model object as a parameter. We can now use it this way: - - -class PictureFile < ActiveRecord::Base - after_destroy PictureFileCallbacks.new -end - - -Note that we needed to instantiate a new +PictureFileCallbacks+ object, since we declared our callback as an instance method. Sometimes it will make more sense to have it as a class method. - - -class PictureFileCallbacks - def self.after_destroy(picture_file) - File.delete(picture_file.filepath) - if File.exists?(picture_file.filepath) - end -end - - -If the callback method is declared this way, it won't be necessary to instantiate a +PictureFileCallbacks+ object. - - -class PictureFile < ActiveRecord::Base - after_destroy PictureFileCallbacks -end - - -You can declare as many callbacks as you want inside your callback classes. - -h3. Observers - -Observers are similar to callbacks, but with important differences. Whereas callbacks can pollute a model with code that isn't directly related to its purpose, observers allow you to add the same functionality outside of a model. For example, it could be argued that a +User+ model should not include code to send registration confirmation emails. Whenever you use callbacks with code that isn't directly related to your model, you may want to consider creating an observer instead. - -h4. Creating Observers - -For example, imagine a +User+ model where we want to send an email every time a new user is created. Because sending emails is not directly related to our model's purpose, we could create an observer to contain this functionality. - - -rails generate observer User - - - -class UserObserver < ActiveRecord::Observer - def after_create(model) - # code to send confirmation email... - end -end - - -As with callback classes, the observer's methods receive the observed model as a parameter. - -h4. Registering Observers - -Observers are conventionally placed inside of your +app/models+ directory and registered in your application's +config/environment.rb+ file. For example, the +UserObserver+ above would be saved as +app/models/user_observer.rb+ and registered in +config/environment.rb+ this way: - - -# Activate observers that should always be running -config.active_record.observers = :user_observer - - -As usual, settings in +config/environments+ take precedence over those in +config/environment.rb+. So, if you prefer that an observer not run in all environments, you can simply register it in a specific environment instead. - -h4. Sharing Observers - -By default, Rails will simply strip "Observer" from an observer's name to find the model it should observe. However, observers can also be used to add behaviour to more than one model, and so it's possible to manually specify the models that our observer should observe. - - -class MailerObserver < ActiveRecord::Observer - observe :registration, :user - - def after_create(model) - # code to send confirmation email... - end -end - - -In this example, the +after_create+ method would be called whenever a +Registration+ or +User+ was created. Note that this new +MailerObserver+ would also need to be registered in +config/environment.rb+ in order to take effect. - - -# Activate observers that should always be running -config.active_record.observers = :mailer_observer - - -h3. Changelog - -"Lighthouse ticket":http://rails.lighthouseapp.com/projects/16213/tickets/26-active-record-validations-and-callbacks - -* May 24, 2010: Fixed document to validate XHTML 1.0 Strict. "Jaime Iniesta":http://jaimeiniesta.com -* May 15, 2010: Validation Errors section updated by "Emili Parreño":http://www.eparreno.com -* March 7, 2009: Callbacks revision by Trevor Turk -* February 10, 2009: Observers revision by Trevor Turk -* February 5, 2009: Initial revision by Trevor Turk -* January 9, 2009: Initial version by "Cássio Marques":credits.html#cmarques diff --git a/railties/guides/source/form_helpers.textile b/railties/guides/source/form_helpers.textile index 515b3aad39..1f1b7d076e 100644 --- a/railties/guides/source/form_helpers.textile +++ b/railties/guides/source/form_helpers.textile @@ -205,7 +205,7 @@ Upon form submission the value entered by the user will be stored in +params[:pe WARNING: You must pass the name of an instance variable, i.e. +:person+ or +"person"+, not an actual instance of your model object. -Rails provides helpers for displaying the validation errors associated with a model object. These are covered in detail by the "Active Record Validations and Callbacks":./activerecord_validations_callbacks.html#displaying-validation-errors-in-the-view guide. +Rails provides helpers for displaying the validation errors associated with a model object. These are covered in detail by the "Active Record Validations and Callbacks":./active_record_validations_callbacks.html#displaying-validation-errors-in-the-view guide. h4. Binding a Form to an Object diff --git a/railties/guides/source/index.html.erb b/railties/guides/source/index.html.erb index 5a715cf9f7..be077fcd2f 100644 --- a/railties/guides/source/index.html.erb +++ b/railties/guides/source/index.html.erb @@ -47,7 +47,7 @@ Ruby on Rails Guides

This guide covers how you can use Active Record migrations to alter your database in a structured and organized manner.

<% end %> -<%= guide("Active Record Validations and Callbacks", 'activerecord_validations_callbacks.html') do %> +<%= guide("Active Record Validations and Callbacks", 'active_record_validations_callbacks.html') do %>

This guide covers how you can use Active Record validations and callbacks.

<% end %> diff --git a/railties/guides/source/layout.html.erb b/railties/guides/source/layout.html.erb index f1727166ba..501d8fef6d 100644 --- a/railties/guides/source/layout.html.erb +++ b/railties/guides/source/layout.html.erb @@ -50,7 +50,7 @@
Getting Started with Rails
Models
Rails Database Migrations
-
Active Record Validations and Callbacks
+
Active Record Validations and Callbacks
Active Record Associations
Active Record Query Interface
Views
-- cgit v1.2.3 From 6d222cb94e5fdb403f9f1f75147ad42e19c5d75b Mon Sep 17 00:00:00 2001 From: Jaime Iniesta Date: Fri, 18 Jun 2010 15:26:07 +0200 Subject: cleaner output for rake validate_guides: dot-style, brief summary and detailed description below --- railties/guides/w3c_validator.rb | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) (limited to 'railties') diff --git a/railties/guides/w3c_validator.rb b/railties/guides/w3c_validator.rb index b55645a7a9..49cfb984cf 100644 --- a/railties/guides/w3c_validator.rb +++ b/railties/guides/w3c_validator.rb @@ -35,18 +35,21 @@ module RailsGuides def validate validator = MarkupValidator.new + STDOUT.sync = true + errors_on_guides = {} guides_to_validate.each do |f| - puts "Validating #{f}" results = validator.validate_file(f) - if !results.validity - puts "#{f} FAILED W3C validation with #{results.errors.size} error(s):" - results.errors.each do |error| - puts error.to_s - end + if results.validity + print "." + else + print "E" + errors_on_guides[f] = results.errors end end + + show_results(errors_on_guides) end private @@ -61,6 +64,26 @@ module RailsGuides prefixes.any? {|p| guide.start_with?("./guides/output/#{p}")} end end + + def show_results(error_list) + if error_list.size == 0 + puts "\n\nAll checked guides validate OK!" + else + error_summary = error_detail = "" + + error_list.each_pair do |name, errors| + error_summary += "\n #{name}" + error_detail += "\n\n #{name} has #{errors.size} validation error(s):\n" + errors.each do |error| + error_detail += "\n "+error.to_s.gsub("\n", "") + end + end + + puts "\n\nThere are #{error_list.size} guides with validation errors:\n" + error_summary + puts "\nHere are the detailed errors for each guide:" + error_detail + end + end + end end -- cgit v1.2.3 From bfc05e244cf9ca81c7fc7d6ee90a9c8b688bf86c Mon Sep 17 00:00:00 2001 From: Antonio Cangiano Date: Fri, 28 May 2010 16:27:14 -0400 Subject: Adds a few connection parameters for IBM databases. [#3852] Signed-off-by: Jeremy Kemper --- .../app/templates/config/databases/ibm_db.yml | 60 +++++++++++++--------- 1 file changed, 36 insertions(+), 24 deletions(-) (limited to 'railties') diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/ibm_db.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/ibm_db.yml index 2784a949fb..df5ef33064 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/databases/ibm_db.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/ibm_db.yml @@ -32,40 +32,52 @@ # please refer to the latest documents at http://rubyforge.org/docman/?group_id=2361 development: - adapter: ibm_db - username: db2inst1 + adapter: ibm_db + username: db2inst1 password: - database: <%= app_name[0,4] %>_dev - #schema: db2inst1 - #host: localhost - #port: 50000 - #account: my_account - #app_user: my_app_user + database: <%= app_name[0,4] %>_dev + #schema: db2inst1 + #host: localhost + #port: 50000 + #account: my_account + #app_user: my_app_user #application: my_application #workstation: my_workstation + #security: SSL + #timeout: 10 + #authentication: SERVER + #parameterized: false test: - adapter: ibm_db - username: db2inst1 + adapter: ibm_db + username: db2inst1 password: - database: <%= app_name[0,4] %>_tst - #schema: db2inst1 - #host: localhost - #port: 50000 - #account: my_account - #app_user: my_app_user + database: <%= app_name[0,4] %>_tst + #schema: db2inst1 + #host: localhost + #port: 50000 + #account: my_account + #app_user: my_app_user #application: my_application #workstation: my_workstation + #security: SSL + #timeout: 10 + #authentication: SERVER + #parameterized: false production: - adapter: ibm_db - username: db2inst1 + adapter: ibm_db + username: db2inst1 password: - database: <%= app_name[0,8] %> - #schema: db2inst1 - #host: localhost - #port: 50000 - #account: my_account - #app_user: my_app_user + database: <%= app_name[0,8] %> + #schema: db2inst1 + #host: localhost + #port: 50000 + #account: my_account + #app_user: my_app_user #application: my_application #workstation: my_workstation + #security: SSL + #timeout: 10 + #authentication: SERVER + #parameterized: false \ No newline at end of file -- cgit v1.2.3 From 312f43324159fbcd8749cd331ed7d6500a714a83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sat, 19 Jun 2010 17:51:29 +0200 Subject: Clear DescendantsTracker on each request. --- railties/lib/rails/application/bootstrap.rb | 2 + .../application/initializers/load_path_test.rb | 2 +- railties/test/application/loading_test.rb | 73 ++++++++++++++++++++++ .../test/application/model_initialization_test.rb | 33 ---------- railties/test/application/rake_test.rb | 2 +- 5 files changed, 77 insertions(+), 35 deletions(-) create mode 100644 railties/test/application/loading_test.rb delete mode 100644 railties/test/application/model_initialization_test.rb (limited to 'railties') diff --git a/railties/lib/rails/application/bootstrap.rb b/railties/lib/rails/application/bootstrap.rb index 0a435f0f36..44e26b5713 100644 --- a/railties/lib/rails/application/bootstrap.rb +++ b/railties/lib/rails/application/bootstrap.rb @@ -1,4 +1,5 @@ require "active_support/notifications" +require "active_support/descendants_tracker" module Rails class Application @@ -55,6 +56,7 @@ module Rails initializer :set_clear_dependencies_hook do unless config.cache_classes ActionDispatch::Callbacks.after do + ActiveSupport::DescendantsTracker.clear ActiveSupport::Dependencies.clear end end diff --git a/railties/test/application/initializers/load_path_test.rb b/railties/test/application/initializers/load_path_test.rb index d31915e129..714d62311d 100644 --- a/railties/test/application/initializers/load_path_test.rb +++ b/railties/test/application/initializers/load_path_test.rb @@ -19,7 +19,7 @@ module ApplicationTests assert $:.include?("#{app_path}/app/models") end - test "initializing an application adds lib path on inheritance hook" do + test "initializing an application allows to load code on lib path inside application class definitation" do app_file "lib/foo.rb", <<-RUBY module Foo; end RUBY diff --git a/railties/test/application/loading_test.rb b/railties/test/application/loading_test.rb new file mode 100644 index 0000000000..b337d3fc6e --- /dev/null +++ b/railties/test/application/loading_test.rb @@ -0,0 +1,73 @@ +require 'isolation/abstract_unit' + +class LoadingTest < Test::Unit::TestCase + include ActiveSupport::Testing::Isolation + + def setup + build_app + boot_rails + end + + def app + @app ||= Rails.application + end + + def test_load_should_load_constants + app_file "app/models/post.rb", <<-MODEL + class Post < ActiveRecord::Base + validates_acceptance_of :title, :accept => "omg" + end + MODEL + + require "#{rails_root}/config/environment" + setup_ar! + + p = Post.create(:title => 'omg') + assert_equal 1, Post.count + assert_equal 'omg', p.title + p = Post.first + assert_equal 'omg', p.title + end + + def test_descendants_are_cleaned_on_each_request_without_cache_classes + add_to_config <<-RUBY + config.cache_classes = false + RUBY + + app_file "app/models/post.rb", <<-MODEL + class Post < ActiveRecord::Base + end + MODEL + + app_file 'config/routes.rb', <<-RUBY + AppTemplate::Application.routes.draw do |map| + match '/load', :to => lambda { |env| [200, {}, Post.all] } + match '/unload', :to => lambda { |env| [200, {}, []] } + end + RUBY + + require 'rack/test' + extend Rack::Test::Methods + + require "#{rails_root}/config/environment" + setup_ar! + + assert_equal [], ActiveRecord::Base.descendants + get "/load" + assert_equal [Post], ActiveRecord::Base.descendants + get "/unload" + assert_equal [], ActiveRecord::Base.descendants + end + + protected + + def setup_ar! + ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:") + ActiveRecord::Migration.verbose = false + ActiveRecord::Schema.define(:version => 1) do + create_table :posts do |t| + t.string :title + end + end + end +end diff --git a/railties/test/application/model_initialization_test.rb b/railties/test/application/model_initialization_test.rb deleted file mode 100644 index 6a22f8d8df..0000000000 --- a/railties/test/application/model_initialization_test.rb +++ /dev/null @@ -1,33 +0,0 @@ -require 'isolation/abstract_unit' - -class PostTest < Test::Unit::TestCase - include ActiveSupport::Testing::Isolation - - def setup - build_app - boot_rails - end - - def test_reload_should_reload_constants - app_file "app/models/post.rb", <<-MODEL - class Post < ActiveRecord::Base - validates_acceptance_of :title, :accept => "omg" - end - MODEL - - require "#{rails_root}/config/environment" - ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:") - ActiveRecord::Migration.verbose = false - ActiveRecord::Schema.define(:version => 1) do - create_table :posts do |t| - t.string :title - end - end - - p = Post.create(:title => 'omg') - assert_equal 1, Post.count - assert_equal 'omg', p.title - p = Post.first - assert_equal 'omg', p.title - end -end diff --git a/railties/test/application/rake_test.rb b/railties/test/application/rake_test.rb index 6b7a471494..40fb446b16 100644 --- a/railties/test/application/rake_test.rb +++ b/railties/test/application/rake_test.rb @@ -9,7 +9,7 @@ module ApplicationTests boot_rails FileUtils.rm_rf("#{app_path}/config/environments") end - + def test_gems_tasks_are_loaded_first_than_application_ones app_file "lib/tasks/app.rake", <<-RUBY $task_loaded = Rake::Task.task_defined?("db:create:all") -- cgit v1.2.3 From ed3f042e99949526f483d1f567e40031deea33d3 Mon Sep 17 00:00:00 2001 From: Andrew White Date: Sat, 19 Jun 2010 22:35:54 +0100 Subject: Make polymorphic_url and scaffolding work with uncountable resources [#3930 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- .../lib/rails/generators/erb/scaffold/templates/edit.html.erb | 2 +- .../lib/rails/generators/erb/scaffold/templates/new.html.erb | 2 +- .../lib/rails/generators/erb/scaffold/templates/show.html.erb | 2 +- railties/lib/rails/generators/named_base.rb | 8 ++++++++ .../rails/scaffold_controller/templates/controller.rb | 2 +- .../generators/test_unit/scaffold/templates/functional_test.rb | 2 +- railties/test/generators/named_base_test.rb | 10 ++++++++++ 7 files changed, 23 insertions(+), 5 deletions(-) (limited to 'railties') diff --git a/railties/lib/rails/generators/erb/scaffold/templates/edit.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/edit.html.erb index 5bc507ffc8..415f820206 100644 --- a/railties/lib/rails/generators/erb/scaffold/templates/edit.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/edit.html.erb @@ -3,4 +3,4 @@ <%%= render 'form' %> <%%= link_to 'Show', @<%= singular_name %> %> | -<%%= link_to 'Back', <%= plural_name %>_path %> +<%%= link_to 'Back', <%= index_helper %>_path %> diff --git a/railties/lib/rails/generators/erb/scaffold/templates/new.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/new.html.erb index 9a1c489331..ddabc9d349 100644 --- a/railties/lib/rails/generators/erb/scaffold/templates/new.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/new.html.erb @@ -2,4 +2,4 @@ <%%= render 'form' %> -<%%= link_to 'Back', <%= plural_name %>_path %> +<%%= link_to 'Back', <%= index_helper %>_path %> diff --git a/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb index 6b3518717a..31b8253b35 100644 --- a/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb @@ -9,4 +9,4 @@ <% end -%> <%%= link_to 'Edit', edit_<%= singular_name %>_path(@<%= singular_name %>) %> | -<%%= link_to 'Back', <%= plural_name %>_path %> +<%%= link_to 'Back', <%= index_helper %>_path %> diff --git a/railties/lib/rails/generators/named_base.rb b/railties/lib/rails/generators/named_base.rb index 8d1dfbd947..72ec2856d0 100644 --- a/railties/lib/rails/generators/named_base.rb +++ b/railties/lib/rails/generators/named_base.rb @@ -46,6 +46,14 @@ module Rails end end + def uncountable? + singular_name == plural_name + end + + def index_helper + uncountable? ? "#{plural_name}_index" : plural_name + end + # Tries to retrieve the application name or simple return application. def application_name if defined?(Rails) && Rails.application diff --git a/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb b/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb index bbdce669dc..b5f19b6d15 100644 --- a/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb +++ b/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb @@ -78,7 +78,7 @@ class <%= controller_class_name %>Controller < ApplicationController @<%= orm_instance.destroy %> respond_to do |format| - format.html { redirect_to(<%= table_name %>_url) } + format.html { redirect_to(<%= index_helper %>_url) } format.xml { head :ok } end end diff --git a/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb b/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb index 4f8ddbffcf..d5d3d6d5cd 100644 --- a/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb +++ b/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb @@ -46,6 +46,6 @@ class <%= controller_class_name %>ControllerTest < ActionController::TestCase delete :destroy, :id => @<%= file_name %>.to_param end - assert_redirected_to <%= table_name %>_path + assert_redirected_to <%= index_helper %>_path end end diff --git a/railties/test/generators/named_base_test.rb b/railties/test/generators/named_base_test.rb index e73dd237fb..1badae0713 100644 --- a/railties/test/generators/named_base_test.rb +++ b/railties/test/generators/named_base_test.rb @@ -93,6 +93,16 @@ class NamedBaseTest < Rails::Generators::TestCase assert_name g, "application", :application_name end + def test_index_helper + g = generator ['Post'] + assert_name g, 'posts', :index_helper + end + + def test_index_helper_with_uncountable + g = generator ['Sheep'] + assert_name g, 'sheep_index', :index_helper + end + protected def assert_name(generator, value, method) -- cgit v1.2.3 From 98a5188f518b1e8cfa9d7aa59856e5b32985eb46 Mon Sep 17 00:00:00 2001 From: Chris Griego Date: Sat, 19 Jun 2010 01:10:57 -0500 Subject: Strip trailing whitespace from generated applications [#4905 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- railties/lib/rails/generators/rails/app/templates/README | 8 ++++---- .../generators/rails/app/templates/config/databases/mysql.yml | 2 +- .../generators/rails/app/templates/config/databases/oracle.yml | 2 +- .../rails/app/templates/config/initializers/inflections.rb | 2 +- .../rails/app/templates/config/initializers/secret_token.rb.tt | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) (limited to 'railties') diff --git a/railties/lib/rails/generators/rails/app/templates/README b/railties/lib/rails/generators/rails/app/templates/README index 9ec6db6d71..e2764dee03 100644 --- a/railties/lib/rails/generators/rails/app/templates/README +++ b/railties/lib/rails/generators/rails/app/templates/README @@ -37,7 +37,7 @@ link:files/vendor/rails/actionpack/README.html. 3. Go to http://localhost:3000/ and you'll see: "Welcome aboard: You're riding the Rails!" -4. Follow the guidelines to start developing your application. You can find +4. Follow the guidelines to start developing your application. You can find the following resources handy: * The Getting Started Guide: http://guides.rubyonrails.org/getting_started.html @@ -71,13 +71,13 @@ The result will be a message in your log file along the lines of: More information on how to use the logger is at http://www.ruby-doc.org/core/ -Also, Ruby documentation can be found at http://www.ruby-lang.org/. There are +Also, Ruby documentation can be found at http://www.ruby-lang.org/. There are several books available online as well: * Programming Ruby: http://www.ruby-doc.org/docs/ProgrammingRuby/ (Pickaxe) * Learn to Program: http://pine.fm/LearnToProgram/ (a beginners guide) -These two books will bring you up to speed on the Ruby language and also on +These two books will bring you up to speed on the Ruby language and also on programming in general. @@ -199,7 +199,7 @@ app/controllers ApplicationController which itself descends from ActionController::Base. app/models - Holds models that should be named like post.rb. Models descend from + Holds models that should be named like post.rb. Models descend from ActiveRecord::Base by default. app/views diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml index 6bf2f7b1fd..ffc8a0a8cb 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml @@ -52,7 +52,7 @@ production: database: <%= app_name %>_production pool: 5 username: root - password: + password: <% if mysql_socket -%> socket: <%= mysql_socket %> <% else -%> diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/oracle.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/oracle.yml index a1883f6256..f99ee937f3 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/databases/oracle.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/oracle.yml @@ -36,4 +36,4 @@ production: adapter: oracle database: <%= app_name %>_production username: <%= app_name %> - password: + password: diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/inflections.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/inflections.rb index d531b8bb82..9e8b0131f8 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/inflections.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/inflections.rb @@ -1,6 +1,6 @@ # Be sure to restart your server when you modify this file. -# Add new inflection rules using the following format +# Add new inflection rules using the following format # (all these examples are active by default): # ActiveSupport::Inflector.inflections do |inflect| # inflect.plural /^(ox)$/i, '\1en' diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/secret_token.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/secret_token.rb.tt index c2fa31aadb..22aa576f5d 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/secret_token.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/secret_token.rb.tt @@ -2,6 +2,6 @@ # Your secret key for verifying the integrity of signed cookies. # If you change this key, all old signed cookies will become invalid! -# Make sure the secret is at least 30 characters and all random, +# Make sure the secret is at least 30 characters and all random, # no regular words or you'll be exposed to dictionary attacks. Rails.application.config.secret_token = '<%= app_secret %>' -- cgit v1.2.3 From 95a8f252c028c94b70cce4888bce42b7e9e30786 Mon Sep 17 00:00:00 2001 From: rohit Date: Wed, 16 Jun 2010 18:50:50 +0530 Subject: remove executable permission from files that don't need it. [#4802 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- railties/guides/assets/javascripts/code_highlighter.js | 0 railties/guides/assets/javascripts/guides.js | 0 railties/guides/assets/stylesheets/print.css | 0 railties/guides/assets/stylesheets/reset.css | 0 railties/guides/assets/stylesheets/style.css | 0 railties/lib/rails/commands/generate.rb | 0 railties/lib/rails/generators/rails/app/templates/Rakefile | 0 7 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 railties/guides/assets/javascripts/code_highlighter.js mode change 100755 => 100644 railties/guides/assets/javascripts/guides.js mode change 100755 => 100644 railties/guides/assets/stylesheets/print.css mode change 100755 => 100644 railties/guides/assets/stylesheets/reset.css mode change 100755 => 100644 railties/guides/assets/stylesheets/style.css mode change 100755 => 100644 railties/lib/rails/commands/generate.rb mode change 100755 => 100644 railties/lib/rails/generators/rails/app/templates/Rakefile (limited to 'railties') diff --git a/railties/guides/assets/javascripts/code_highlighter.js b/railties/guides/assets/javascripts/code_highlighter.js old mode 100755 new mode 100644 diff --git a/railties/guides/assets/javascripts/guides.js b/railties/guides/assets/javascripts/guides.js old mode 100755 new mode 100644 diff --git a/railties/guides/assets/stylesheets/print.css b/railties/guides/assets/stylesheets/print.css old mode 100755 new mode 100644 diff --git a/railties/guides/assets/stylesheets/reset.css b/railties/guides/assets/stylesheets/reset.css old mode 100755 new mode 100644 diff --git a/railties/guides/assets/stylesheets/style.css b/railties/guides/assets/stylesheets/style.css old mode 100755 new mode 100644 diff --git a/railties/lib/rails/commands/generate.rb b/railties/lib/rails/commands/generate.rb old mode 100755 new mode 100644 diff --git a/railties/lib/rails/generators/rails/app/templates/Rakefile b/railties/lib/rails/generators/rails/app/templates/Rakefile old mode 100755 new mode 100644 -- cgit v1.2.3 From bb324693ab8e197b369b90e2c3b46d67395a58e5 Mon Sep 17 00:00:00 2001 From: Ryan Duryea Date: Tue, 4 May 2010 11:49:22 -0700 Subject: Pass rack the absolute path of server's pid file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When running as a daemon, rack will cd to "/" and paths relative to the root of the rails app aren't valid when rack is setting up. Because of this, "rails server -d" was failing silently when trying to write it's pid file Signed-off-by: José Valim --- railties/lib/rails/commands/server.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'railties') diff --git a/railties/lib/rails/commands/server.rb b/railties/lib/rails/commands/server.rb index 3f74cd49fc..861baa297e 100644 --- a/railties/lib/rails/commands/server.rb +++ b/railties/lib/rails/commands/server.rb @@ -83,7 +83,7 @@ module Rails :environment => (ENV['RAILS_ENV'] || "development").dup, :daemonize => false, :debugger => false, - :pid => "tmp/pids/server.pid" + :pid => File.expand_path("tmp/pids/server.pid") }) end end -- cgit v1.2.3 From 73df48083a8e0bdb10752c1b481549caac35b6cf Mon Sep 17 00:00:00 2001 From: Ryan Duryea Date: Wed, 5 May 2010 11:42:10 -0700 Subject: Added absolute path for config.ru as well. Turns out this is also needed to fix the daemon issue under ruby 1.8.7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [#4531 state:resolved] Signed-off-by: José Valim --- railties/lib/rails/commands/server.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'railties') diff --git a/railties/lib/rails/commands/server.rb b/railties/lib/rails/commands/server.rb index 861baa297e..cb9b871875 100644 --- a/railties/lib/rails/commands/server.rb +++ b/railties/lib/rails/commands/server.rb @@ -83,7 +83,8 @@ module Rails :environment => (ENV['RAILS_ENV'] || "development").dup, :daemonize => false, :debugger => false, - :pid => File.expand_path("tmp/pids/server.pid") + :pid => File.expand_path("tmp/pids/server.pid"), + :config => File.expand_path("config.ru") }) end end -- cgit v1.2.3 From d06105063829d44adf641059ef97f54d7b690f4b Mon Sep 17 00:00:00 2001 From: rohit Date: Sun, 20 Jun 2010 07:38:06 +0530 Subject: Add test for migration generator with name not starting with add or remove. [#4835 state:committed] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- railties/test/generators/migration_generator_test.rb | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'railties') diff --git a/railties/test/generators/migration_generator_test.rb b/railties/test/generators/migration_generator_test.rb index 6ea722e239..f9d1e42d24 100644 --- a/railties/test/generators/migration_generator_test.rb +++ b/railties/test/generators/migration_generator_test.rb @@ -62,4 +62,19 @@ class MigrationGeneratorTest < Rails::Generators::TestCase end end end + + def test_should_create_empty_migrations_if_name_not_start_with_add_or_remove + migration = "create_books" + run_generator [migration, "title:string", "content:text"] + + assert_migration "db/migrate/#{migration}.rb" do |content| + assert_class_method :up, content do |up| + assert_match /^\s*$/, up + end + + assert_class_method :down, content do |down| + assert_match /^\s*$/, down + end + end + end end -- cgit v1.2.3 From 9e081caee74e6d08035a8835899dcc566536a871 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sun, 20 Jun 2010 13:03:08 +0200 Subject: Improve documentation for add_lib_to_load_paths! --- railties/lib/rails/application.rb | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'railties') diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index 85ae8cbbb1..b410639272 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -84,17 +84,30 @@ module Rails delegate :middleware, :to => :config - def add_lib_to_load_paths! + # This method is called just after an application inherits from Rails::Application, + # allowing the developer to load classes in lib and use them during application + # configuration. + # + # class MyApplication < Rails::Application + # require "my_backend" # in lib/my_backend + # config.i18n.backend = MyBackend + # end + # + # Notice this method takes into consideration the default root path. So if you + # are changing config.root inside your application definition or having a custom + # Rails application, you will need to add lib to $LOAD_PATH on your own in case + # you need to load files in lib/ during the application configuration as well. + def add_lib_to_load_paths! #:nodoc: path = config.root.join('lib').to_s $LOAD_PATH.unshift(path) if File.exists?(path) end - def require_environment! + def require_environment! #:nodoc: environment = paths.config.environment.to_a.first require environment if environment end - def eager_load! + def eager_load! #:nodoc: railties.all(&:eager_load!) super end -- cgit v1.2.3 From 772c2b0b862850c29e7f112a5ddeaf1c0ed06408 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sun, 20 Jun 2010 13:37:58 +0200 Subject: Use the new ActiveSupport::FileUpdateChecker instead of RoutesReloader. --- railties/lib/rails/application.rb | 13 +++++-- railties/lib/rails/application/routes_reloader.rb | 46 ----------------------- 2 files changed, 10 insertions(+), 49 deletions(-) delete mode 100644 railties/lib/rails/application/routes_reloader.rb (limited to 'railties') diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index b410639272..8b8ef20b1f 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -1,4 +1,5 @@ require 'active_support/core_ext/hash/reverse_merge' +require 'active_support/file_update_checker' require 'fileutils' require 'rails/plugin' require 'rails/engine' @@ -46,7 +47,6 @@ module Rails autoload :Configuration, 'rails/application/configuration' autoload :Finisher, 'rails/application/finisher' autoload :Railties, 'rails/application/railties' - autoload :RoutesReloader, 'rails/application/routes_reloader' class << self private :new @@ -121,11 +121,18 @@ module Rails end def routes_reloader - @routes_reloader ||= RoutesReloader.new + @routes_reloader ||= ActiveSupport::FileUpdateChecker.new([]){ reload_routes! } end def reload_routes! - routes_reloader.reload! + routes = Rails::Application.routes + routes.disable_clear_and_finalize = true + + routes.clear! + routes_reloader.paths.each { |path| load(path) } + ActiveSupport.on_load(:action_controller) { routes.finalize! } + ensure + routes.disable_clear_and_finalize = false end def initialize! diff --git a/railties/lib/rails/application/routes_reloader.rb b/railties/lib/rails/application/routes_reloader.rb deleted file mode 100644 index a2b3622df8..0000000000 --- a/railties/lib/rails/application/routes_reloader.rb +++ /dev/null @@ -1,46 +0,0 @@ -module Rails - class Application - class RoutesReloader - attr_reader :paths - - def initialize - @paths, @last_change_at = [], nil - end - - def changed_at - routes_changed_at = nil - - paths.each do |path| - config_changed_at = File.stat(path).mtime - - if routes_changed_at.nil? || config_changed_at > routes_changed_at - routes_changed_at = config_changed_at - end - end - - routes_changed_at - end - - def reload! - routes = Rails::Application.routes - routes.disable_clear_and_finalize = true - - routes.clear! - paths.each { |path| load(path) } - ActiveSupport.on_load(:action_controller) { routes.finalize! } - - nil - ensure - routes.disable_clear_and_finalize = false - end - - def reload_if_changed - current_change_at = changed_at - if @last_change_at != current_change_at - @last_change_at = current_change_at - reload! - end - end - end - end -end \ No newline at end of file -- cgit v1.2.3 From dad80ad7862834543783974a22d316f074cfee66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sun, 20 Jun 2010 14:44:38 +0200 Subject: I18n.reload! is only called if any of the locale files actually changed. --- .../test/application/initializers/i18n_test.rb | 133 ++++++++++++++++++--- railties/test/railties/i18n_railtie_test.rb | 89 -------------- 2 files changed, 114 insertions(+), 108 deletions(-) delete mode 100644 railties/test/railties/i18n_railtie_test.rb (limited to 'railties') diff --git a/railties/test/application/initializers/i18n_test.rb b/railties/test/application/initializers/i18n_test.rb index 99b2d86013..a1fcba3310 100644 --- a/railties/test/application/initializers/i18n_test.rb +++ b/railties/test/application/initializers/i18n_test.rb @@ -8,48 +8,143 @@ module ApplicationTests build_app boot_rails FileUtils.rm_rf "#{app_path}/config/environments" + require "rails/all" end - # i18n + def load_app + require "#{app_path}/config/environment" + end + + def app + @app ||= Rails::Application + end + + def assert_fallbacks(fallbacks) + fallbacks.each do |locale, expected| + actual = I18n.fallbacks[locale] + assert_equal expected, actual, "expected fallbacks for #{locale.inspect} to be #{expected.inspect}, but were #{actual.inspect}" + end + end + + def assert_no_fallbacks + assert !I18n.backend.class.included_modules.include?(I18n::Backend::Fallbacks) + end + + # Locales test "setting another default locale" do add_to_config <<-RUBY - config.root = "#{app_path}" config.i18n.default_locale = :de RUBY - require "#{app_path}/config/environment" + load_app assert_equal :de, I18n.default_locale end + # Load paths test "no config locales dir present should return empty load path" do FileUtils.rm_rf "#{app_path}/config/locales" - add_to_config <<-RUBY - config.root = "#{app_path}" - RUBY - require "#{app_path}/config/environment" - + load_app assert_equal [], Rails.application.config.i18n.load_path end - test "config locales dir present should be added to load path" do + test "locale files should be added to the load path" do + app_file "config/another_locale.yml", "" + add_to_config <<-RUBY - config.root = "#{app_path}" + config.i18n.load_path << config.root.join("config/another_locale.yml").to_s RUBY - require "#{app_path}/config/environment" - assert_equal ["#{app_path}/config/locales/en.yml"], Rails.application.config.i18n.load_path + load_app + assert_equal [ + "#{app_path}/config/locales/en.yml", "#{app_path}/config/another_locale.yml" + ], Rails.application.config.i18n.load_path + + assert I18n.load_path.include?("#{app_path}/config/locales/en.yml") + assert I18n.load_path.include?("#{app_path}/config/another_locale.yml") end - test "config defaults should be added with config settings" do + test "locales are reloaded if they change between requests" do add_to_config <<-RUBY - config.root = "#{app_path}" - config.i18n.load_path << "my/other/locale.yml" + config.cache_classes = false RUBY - require "#{app_path}/config/environment" - assert_equal [ - "#{app_path}/config/locales/en.yml", "my/other/locale.yml" - ], Rails.application.config.i18n.load_path + app_file "config/locales/en.yml", <<-YAML +en: + foo: "1" + YAML + + app_file 'config/routes.rb', <<-RUBY + AppTemplate::Application.routes.draw do |map| + match '/i18n', :to => lambda { |env| [200, {}, [I18n.t(:foo)]] } + end + RUBY + + require 'rack/test' + extend Rack::Test::Methods + load_app + + get "/i18n" + assert_equal "1", last_response.body + + app_file "config/locales/en.yml", <<-YAML +en: + foo: "2" + YAML + + get "/i18n" + assert_equal "2", last_response.body + end + + # Fallbacks + test "not using config.i18n.fallbacks does not initialize I18n.fallbacks" do + I18n.backend = Class.new { include I18n::Backend::Base }.new + load_app + assert_no_fallbacks + end + + test "config.i18n.fallbacks = true initializes I18n.fallbacks with default settings" do + I18n::Railtie.config.i18n.fallbacks = true + load_app + assert I18n.backend.class.included_modules.include?(I18n::Backend::Fallbacks) + assert_fallbacks :de => [:de, :en] + end + + test "config.i18n.fallbacks = true initializes I18n.fallbacks with default settings even when backend changes" do + I18n::Railtie.config.i18n.fallbacks = true + I18n::Railtie.config.i18n.backend = Class.new { include I18n::Backend::Base }.new + load_app + assert I18n.backend.class.included_modules.include?(I18n::Backend::Fallbacks) + assert_fallbacks :de => [:de, :en] + end + + test "config.i18n.fallbacks.defaults = [:'en-US'] initializes fallbacks with en-US as a fallback default" do + I18n::Railtie.config.i18n.fallbacks.defaults = [:'en-US'] + load_app + assert_fallbacks :de => [:de, :'en-US', :en] + end + + test "config.i18n.fallbacks.map = { :ca => :'es-ES' } initializes fallbacks with a mapping ca => es-ES" do + I18n::Railtie.config.i18n.fallbacks.map = { :ca => :'es-ES' } + load_app + assert_fallbacks :ca => [:ca, :"es-ES", :es, :en] + end + + test "[shortcut] config.i18n.fallbacks = [:'en-US'] initializes fallbacks with en-US as a fallback default" do + I18n::Railtie.config.i18n.fallbacks = [:'en-US'] + load_app + assert_fallbacks :de => [:de, :'en-US', :en] + end + + test "[shortcut] config.i18n.fallbacks = [{ :ca => :'es-ES' }] initializes fallbacks with a mapping de-AT => de-DE" do + I18n::Railtie.config.i18n.fallbacks.map = { :ca => :'es-ES' } + load_app + assert_fallbacks :ca => [:ca, :"es-ES", :es, :en] + end + + test "[shortcut] config.i18n.fallbacks = [:'en-US', { :ca => :'es-ES' }] initializes fallbacks with the given arguments" do + I18n::Railtie.config.i18n.fallbacks = [:'en-US', { :ca => :'es-ES' }] + load_app + assert_fallbacks :ca => [:ca, :"es-ES", :es, :'en-US', :en] end end end \ No newline at end of file diff --git a/railties/test/railties/i18n_railtie_test.rb b/railties/test/railties/i18n_railtie_test.rb deleted file mode 100644 index 2b1950b3d5..0000000000 --- a/railties/test/railties/i18n_railtie_test.rb +++ /dev/null @@ -1,89 +0,0 @@ -require "isolation/abstract_unit" - -module RailtiesTest - class I18nRailtieTest < Test::Unit::TestCase - include ActiveSupport::Testing::Isolation - - def setup - build_app - boot_rails - FileUtils.rm_rf("#{app_path}/config/environments") - require "rails/all" - end - - def load_app - require "#{app_path}/config/environment" - end - - def assert_fallbacks(fallbacks) - fallbacks.each do |locale, expected| - actual = I18n.fallbacks[locale] - assert_equal expected, actual, "expected fallbacks for #{locale.inspect} to be #{expected.inspect}, but were #{actual.inspect}" - end - end - - def assert_no_fallbacks - assert !I18n.backend.class.included_modules.include?(I18n::Backend::Fallbacks) - end - - test "config.i18n.load_path gets added to I18n.load_path" do - I18n.load_path = ['existing/path/to/locales'] - I18n::Railtie.config.i18n.load_path = ['new/path/to/locales'] - load_app - - assert I18n.load_path.include?('existing/path/to/locales') - assert I18n.load_path.include?('new/path/to/locales') - end - - test "not using config.i18n.fallbacks does not initialize I18n.fallbacks" do - I18n.backend = Class.new { include I18n::Backend::Base }.new - load_app - assert_no_fallbacks - end - - test "config.i18n.fallbacks = true initializes I18n.fallbacks with default settings" do - I18n::Railtie.config.i18n.fallbacks = true - load_app - assert I18n.backend.class.included_modules.include?(I18n::Backend::Fallbacks) - assert_fallbacks :de => [:de, :en] - end - - test "config.i18n.fallbacks = true initializes I18n.fallbacks with default settings even when backend changes" do - I18n::Railtie.config.i18n.fallbacks = true - I18n::Railtie.config.i18n.backend = Class.new { include I18n::Backend::Base }.new - load_app - assert I18n.backend.class.included_modules.include?(I18n::Backend::Fallbacks) - assert_fallbacks :de => [:de, :en] - end - - test "config.i18n.fallbacks.defaults = [:'en-US'] initializes fallbacks with en-US as a fallback default" do - I18n::Railtie.config.i18n.fallbacks.defaults = [:'en-US'] - load_app - assert_fallbacks :de => [:de, :'en-US', :en] - end - - test "config.i18n.fallbacks.map = { :ca => :'es-ES' } initializes fallbacks with a mapping ca => es-ES" do - I18n::Railtie.config.i18n.fallbacks.map = { :ca => :'es-ES' } - load_app - assert_fallbacks :ca => [:ca, :"es-ES", :es, :en] - end - - test "[shortcut] config.i18n.fallbacks = [:'en-US'] initializes fallbacks with en-US as a fallback default" do - I18n::Railtie.config.i18n.fallbacks = [:'en-US'] - load_app - assert_fallbacks :de => [:de, :'en-US', :en] - end - - test "[shortcut] config.i18n.fallbacks = [{ :ca => :'es-ES' }] initializes fallbacks with a mapping de-AT => de-DE" do - I18n::Railtie.config.i18n.fallbacks.map = { :ca => :'es-ES' } - load_app - assert_fallbacks :ca => [:ca, :"es-ES", :es, :en] - end - - test "[shortcut] config.i18n.fallbacks = [:'en-US', { :ca => :'es-ES' }] initializes fallbacks with the given arguments" do - I18n::Railtie.config.i18n.fallbacks = [:'en-US', { :ca => :'es-ES' }] - load_app - assert_fallbacks :ca => [:ca, :"es-ES", :es, :'en-US', :en] - end - end -end \ No newline at end of file -- cgit v1.2.3 From b083bf2410509ce89492ebb77d4fe877771ab033 Mon Sep 17 00:00:00 2001 From: rspeicher Date: Sun, 20 Jun 2010 16:15:11 -0400 Subject: Generators Guide: Remove semicolons from prologue, as none of the other guides had them --- railties/guides/source/generators.textile | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'railties') diff --git a/railties/guides/source/generators.textile b/railties/guides/source/generators.textile index 704a8793b2..106be1b6cd 100644 --- a/railties/guides/source/generators.textile +++ b/railties/guides/source/generators.textile @@ -4,12 +4,12 @@ Rails generators are an essential tool if you plan to improve your workflow and In this guide you will: -* Learn how to see which generators are available in your application; -* Create a generator using templates; -* Learn how Rails searches for generators before invoking them; -* Customize your scaffold by creating new generators; -* Customize your scaffold by changing generators templates; -* Learn how to use fallbacks to avoid overwriting a huge set of generators; +* Learn how to see which generators are available in your application +* Create a generator using templates +* Learn how Rails searches for generators before invoking them +* Customize your scaffold by creating new generators +* Customize your scaffold by changing generators templates +* Learn how to use fallbacks to avoid overwriting a huge set of generators endprologue. -- cgit v1.2.3 From 1cc71d7931432228e266b3c62180f53b49c551cc Mon Sep 17 00:00:00 2001 From: rspeicher Date: Sun, 20 Jun 2010 16:33:55 -0400 Subject: Generators Guide: Make titles conform to conventions --- railties/guides/source/generators.textile | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'railties') diff --git a/railties/guides/source/generators.textile b/railties/guides/source/generators.textile index 106be1b6cd..0edfec8d53 100644 --- a/railties/guides/source/generators.textile +++ b/railties/guides/source/generators.textile @@ -1,4 +1,4 @@ -h2. Creating and customizing Rails Generators +h2. Creating and Customizing Rails Generators Rails generators are an essential tool if you plan to improve your workflow and in this guide you will learn how to create and customize already existing generators. @@ -15,7 +15,7 @@ endprologue. NOTE: This guide is about Rails generators for versions >= 3.0. Rails generators from previous versions are not supported. -h3. First contact +h3. First Contact When you create an application using the +rails+ command, you are in fact using a Rails generator. After that, you can get a list of all available generators by just invoking +rails generate+: @@ -31,7 +31,7 @@ You will get a list of all generators that comes with Rails. If you need a detai $ rails generate helper --help -h3. Creating your first generator +h3. Creating Your First Generator Since Rails 3.0, generators are built on top of "Thor":http://github.com/wycats/thor. Thor has a powerful options parsing and a great API for manipulating files. For instance, let's build a generator that creates an initializer file named +initializer.rb+ inside +config/initializers+. @@ -72,7 +72,7 @@ end Now we can see the new description by invoking +--help+ in the new generator. The second way to add a description is by creating a file named +USAGE+ in the same directory as our generator. We are going to do that in the next step. -h3. Creating generators with generators +h3. Creating Generators with Generators A faster way to create a generator is using the generator's generator: @@ -129,7 +129,7 @@ $ rails generate initializer foo We can see that now a initializer named foo was created at +config/initializers/foo.rb+ with the contents of our template. That means that copy_file copied a file in our source root to the destination path we gave. The method +file_name+ is automatically created when we inherit from +Rails::Generators::NamedBase+. -h3. Generators lookup +h3. Generators Lookup With our first generator created, we must discuss briefly generators lookup. The way Rails finds generators is exactly the same way Ruby find files, i.e. using +$LOAD_PATHS+. @@ -144,7 +144,7 @@ generators/initializer_generator.rb If none of them is found, it raises an error message. -h3. Customizing your workflow +h3. Customizing Your Workflow Rails generators are flexible enough to let you customize your scaffold the way you want. In your +config/application.rb+ there is a section just for generators: @@ -285,7 +285,7 @@ Now, when the helper generator is invoked and let's say test unit is configured And now you can re-run scaffold for another resource and see it generating tests as well! -h3. Customizing your workflow by changing generators templates +h3. Customizing Your Workflow by Changing Generators Templates In the step above, we simply wanted to add a line to the generated helper, without adding any extra functionality. There is a simpler way to do that, and it's by replacing the templates of already existing generators. @@ -310,7 +310,7 @@ end If you generate another resource, you can see that we got exactly the same result! This is useful if you want to customize your scaffold templates and/or layout by just creating +edit.html.erb+, +index.html.erb+ and so on inside +RAILS_APP/lib/templates/erb/scaffold+. -h3. Adding generators fallbacks +h3. Adding Generators Fallbacks One last feature about generators which is quite useful for plugin generators is fallbacks. For example, imagine that you want to add a feature on top of TestUnit test framework, like "shoulda":http://github.com/thoughtbot/shoulda does. Since TestUnit already implements all generators required by Rails and shoulda just want to overwrite part of it, there is no need for shoulda to reimplement some generators again, they can simply tell Rails to use a +TestUnit+ generator if none was found under +Shoulda+ namespace. -- cgit v1.2.3 From 1168d6523747c006d770ba3521cf8b47956e5e15 Mon Sep 17 00:00:00 2001 From: rspeicher Date: Sun, 20 Jun 2010 16:39:44 -0400 Subject: Generators Guide: Style/grammar changes and minor typos --- railties/guides/source/generators.textile | 48 +++++++++++++++---------------- 1 file changed, 24 insertions(+), 24 deletions(-) (limited to 'railties') diff --git a/railties/guides/source/generators.textile b/railties/guides/source/generators.textile index 0edfec8d53..c5e7980102 100644 --- a/railties/guides/source/generators.textile +++ b/railties/guides/source/generators.textile @@ -8,7 +8,7 @@ In this guide you will: * Create a generator using templates * Learn how Rails searches for generators before invoking them * Customize your scaffold by creating new generators -* Customize your scaffold by changing generators templates +* Customize your scaffold by changing generator templates * Learn how to use fallbacks to avoid overwriting a huge set of generators endprologue. @@ -25,7 +25,7 @@ $ cd myapp $ rails generate -You will get a list of all generators that comes with Rails. If you need a detailed description, for instance about the helper generator, you can simply do: +You will get a list of all generators that comes with Rails. If you need a detailed description of the helper generator, for example, you can simply do: $ rails generate helper --help @@ -33,7 +33,7 @@ $ rails generate helper --help h3. Creating Your First Generator -Since Rails 3.0, generators are built on top of "Thor":http://github.com/wycats/thor. Thor has a powerful options parsing and a great API for manipulating files. For instance, let's build a generator that creates an initializer file named +initializer.rb+ inside +config/initializers+. +Since Rails 3.0, generators are built on top of "Thor":http://github.com/wycats/thor. Thor provides power options parsing and a great API for manipulating files. For instance, let's build a generator that creates an initializer file named +initializer.rb+ inside +config/initializers+. The first step is to create a file at +RAILS_APP/lib/generators/initializer_generator.rb+ with the following content: @@ -45,7 +45,7 @@ class InitializerGenerator < Rails::Generators::Base end
-Our new generator is quite simple: it inherits from +Rails::Generators::Base+ and have one method definition. Each public method in the generator is executed when a generator is invoked. Finally, we invoke the +create_file+ method that will create a file at the given destination with the given content. If you are familiar with Rails Application Templates API, you are at home with new generators API. +Our new generator is quite simple: it inherits from +Rails::Generators::Base+ and has one method definition. Each public method in the generator is executed when a generator is invoked. Finally, we invoke the +create_file+ method that will create a file at the given destination with the given content. If you are familiar with the Rails Application Templates API, you'll feel right at home with the new generators API. To invoke our new generator, we just need to do: @@ -59,7 +59,7 @@ Before we go on, let's see our brand new generator description: $ rails generate initializer --help -Rails usually is able to generate good descriptions if a generator is namespaced, as +ActiveRecord::Generators::ModelGenerator+, but not in this particular case. We can solve this problem in two ways. The first one is calling +desc+ inside our generator: +Rails is usually able to generate good descriptions if a generator is namespaced, as +ActiveRecord::Generators::ModelGenerator+, but not in this particular case. We can solve this problem in two ways. The first one is calling +desc+ inside our generator: class InitializerGenerator < Rails::Generators::Base @@ -70,7 +70,7 @@ class InitializerGenerator < Rails::Generators::Base end -Now we can see the new description by invoking +--help+ in the new generator. The second way to add a description is by creating a file named +USAGE+ in the same directory as our generator. We are going to do that in the next step. +Now we can see the new description by invoking +--help+ on the new generator. The second way to add a description is by creating a file named +USAGE+ in the same directory as our generator. We are going to do that in the next step. h3. Creating Generators with Generators @@ -84,7 +84,7 @@ $ rails generate generator initializer create lib/generators/initializer/templates -And it will create a new generator as follow: +And it will create a new generator as follows: class InitializerGenerator < Rails::Generators::NamedBase @@ -92,7 +92,7 @@ class InitializerGenerator < Rails::Generators::NamedBase end -At first, we can notice that we are inheriting from +Rails::Generators::NamedBase+ instead of +Rails::Generators::Base+. This means that our generator expects as least one argument, which will be the name of the initializer. +First, notice that we are inheriting from +Rails::Generators::NamedBase+ instead of +Rails::Generators::Base+. This means that our generator expects as least one argument, which will be the name of the initializer. We can see that by invoking the description of this new generator (don't forget to delete the old generator file): @@ -127,13 +127,13 @@ And let's execute our generator: $ rails generate initializer foo -We can see that now a initializer named foo was created at +config/initializers/foo.rb+ with the contents of our template. That means that copy_file copied a file in our source root to the destination path we gave. The method +file_name+ is automatically created when we inherit from +Rails::Generators::NamedBase+. +We can see that now a initializer named foo was created at +config/initializers/foo.rb+ with the contents of our template. That means that +copy_file+ copied a file in our source root to the destination path we gave. The method +file_name+ is automatically created when we inherit from +Rails::Generators::NamedBase+. h3. Generators Lookup -With our first generator created, we must discuss briefly generators lookup. The way Rails finds generators is exactly the same way Ruby find files, i.e. using +$LOAD_PATHS+. +Now that we've created our first generator, we need to briefly discuss generator lookup. The way Rails finds generators is exactly the same way Ruby find files, i.e. using +$LOAD_PATHS+. -For instance, when you say +rails g initializer foo+, rails knows you want to invoke the initializer generator and then search for the following generators in the $LOAD_PATHS: +For instance, when you say +rails generate initializer foo+, Rails knows you want to invoke the initializer generator and then search for the following generators in the $LOAD_PATHS: rails/generators/initializer/initializer_generator.rb @@ -156,7 +156,7 @@ config.generators do |g| end
-Before we customize our workflow, let's first see how our scaffold looks like: +Before we customize our workflow, let's first see what our scaffold looks like: $ rails generate scaffold User name:string @@ -186,7 +186,7 @@ $ rails generate scaffold User name:string create public/stylesheets/scaffold.css -Looking at this output, is easy to understand how generators work on Rails 3.0 and above. The scaffold generator actually doesn't generate anything, it just invokes others to do the work. This allows us to add/replace/remove any of those invocations. For instance, the scaffold generator invokes the scaffold_controller generator, which invokes erb, test_unit and helper generators. Since each generator has a single responsibility, they are easy to reuse, avoiding code duplication. +Looking at this output, it's easy to understand how generators work on Rails 3.0 and above. The scaffold generator doesn't actually generate anything, it just invokes others to do the work. This allows us to add/replace/remove any of those invocations. For instance, the scaffold generator invokes the scaffold_controller generator, which invokes erb, test_unit and helper generators. Since each generator has a single responsibility, they are easy to reuse, avoiding code duplication. Our first customization on the workflow will be to stop generating stylesheets and test fixtures on scaffold. We can achieve that by changing our application to the following: @@ -199,15 +199,15 @@ config.generators do |g| end
-If we generate another resource on scaffold, we can notice that neither stylesheets nor fixtures are created anymore. If you want to customize it further, for example to use +Datamapper+ and +Rspec+ instead of +ActiveRecord+ and +TestUnit+, is just a matter of adding their gems to your application and configuring your generators. +If we generate another resource on scaffold, we can notice that neither stylesheets nor fixtures are created anymore. If you want to customize it further, for example to use +Datamapper+ and +RSpec+ instead of +ActiveRecord+ and +TestUnit+, it's just a matter of adding their gems to your application and configuring your generators. -To show that, we are going to create a new helper generator that simply adds some instance variable readers. First, we create a generator: +To demonstrate this, we are going to create a new helper generator that simply adds some instance variable readers. First, we create a generator: $ rails generate generator my_helper -After that, we can delete both templates directory and the +source_root+ class method from our new generators, because we are not going to need them. So our new generator looks like the following: +After that, we can delete both the +templates+ directory and the +source_root+ class method from our new generators, because we are not going to need them. So our new generator looks like the following: class MyHelperGenerator < Rails::Generators::NamedBase @@ -227,7 +227,7 @@ We can try out our new generator by creating a helper for users: $ rails generate my_helper users -And it will generate the following helper file in app/helpers: +And it will generate the following helper file in +app/helpers+: module UsersHelper @@ -258,7 +258,7 @@ $ rails generate scaffold Post body:text We can notice on the output that our new helper was invoked instead of the Rails default. However one thing is missing, which is tests for our new generator and to do that, we are going to reuse old helpers test generators. -Since Rails 3.0, this is easy to do due to the hooks concept. Our new helper does not need to be focused in one specific test framework, it can simply provide a hook and a test framework just need to implement this hook in order to be compatible. +Since Rails 3.0, this is easy to do due to the hooks concept. Our new helper does not need to be focused in one specific test framework, it can simply provide a hook and a test framework just needs to implement this hook in order to be compatible. To do that, we can change your generator to the following: @@ -276,7 +276,7 @@ end end -Now, when the helper generator is invoked and let's say test unit is configured as test framework, it will try to invoke both +MyHelper::Generators::TestUnitGenerator+ and +TestUnit::Generators::MyHelperGenerator+. Since none of those are defined, we can tell our generator to invoke +TestUnit::Generators::HelperGenerator+ instead, which is defined since it's a Rails generator. To do that, we just need to add: +Now, when the helper generator is invoked and TestUnit is configured as the test framekwork, it will try to invoke both +MyHelper::Generators::TestUnitGenerator+ and +TestUnit::Generators::MyHelperGenerator+. Since none of those are defined, we can tell our generator to invoke +TestUnit::Generators::HelperGenerator+ instead, which is defined since it's a Rails generator. To do that, we just need to add: # Search for :helper instead of :my_helper @@ -289,7 +289,7 @@ h3. Customizing Your Workflow by Changing Generators Templates In the step above, we simply wanted to add a line to the generated helper, without adding any extra functionality. There is a simpler way to do that, and it's by replacing the templates of already existing generators. -In Rails 3.0 and above, generators does not look only in the source root for templates, they also search for templates in other paths. And one of them is inside +RAILS_APP/lib/templates+. Since we want to customize +Rails::Generators::HelperGenerator+, we can do that by simple making a template copy inside +RAILS_APP/lib/templates/rails/helper+ with the name +helper.rb+. So let's create such file with the following content: +In Rails 3.0 and above, generators don't just look in the source root for templates, they also search for templates in other paths. And one of them is inside +RAILS_APP/lib/templates+. Since we want to customize +Rails::Generators::HelperGenerator+, we can do that by simply making a template copy inside +RAILS_APP/lib/templates/rails/helper+ with the name +helper.rb+. So let's create that file with the following content: module <%= class_name %>Helper @@ -312,7 +312,7 @@ If you generate another resource, you can see that we got exactly the same resul h3. Adding Generators Fallbacks -One last feature about generators which is quite useful for plugin generators is fallbacks. For example, imagine that you want to add a feature on top of TestUnit test framework, like "shoulda":http://github.com/thoughtbot/shoulda does. Since TestUnit already implements all generators required by Rails and shoulda just want to overwrite part of it, there is no need for shoulda to reimplement some generators again, they can simply tell Rails to use a +TestUnit+ generator if none was found under +Shoulda+ namespace. +One last feature about generators which is quite useful for plugin generators is fallbacks. For example, imagine that you want to add a feature on top of TestUnit test framework, like "shoulda":http://github.com/thoughtbot/shoulda does. Since TestUnit already implements all generators required by Rails and shoulda just wants to overwrite part of it, there is no need for shoulda to reimplement some generators again, it can simply tell Rails to use a +TestUnit+ generator if none was found under the +Shoulda+ namespace. We can easily simulate this behavior by changing our +config/application.rb+ once again: @@ -324,11 +324,11 @@ config.generators do |g| g.stylesheets false # Add a fallback! - g.fallbacks[:should] = :test_unit + g.fallbacks[:shoulda] = :test_unit end -Now, if create a Comment scaffold, you will see that shoulda generators are being invoked, and at the end, they are just falling back to test unit generators: +Now, if you create a Comment scaffold, you will see that the shoulda generators are being invoked, and at the end, they are just falling back to test unit generators: $ rails generate scaffold Comment body:text @@ -357,7 +357,7 @@ $ rails generate scaffold Comment body:text create test/unit/helpers/comments_helper_test.rb -Such tool allows your generators to have single responsibility, increasing the code reuse and reducing the amount of duplication. +Fallbacks allow your generators to have a single responsibility, increasing code reuse and reducing the amount of duplication. h3. Changelog -- cgit v1.2.3 From 31cadc730a40281950a265ff6982dd76cc326828 Mon Sep 17 00:00:00 2001 From: rspeicher Date: Sun, 20 Jun 2010 16:42:20 -0400 Subject: Generators Guide: Typo of my own --- railties/guides/source/generators.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'railties') diff --git a/railties/guides/source/generators.textile b/railties/guides/source/generators.textile index c5e7980102..f39451f243 100644 --- a/railties/guides/source/generators.textile +++ b/railties/guides/source/generators.textile @@ -276,7 +276,7 @@ end end -Now, when the helper generator is invoked and TestUnit is configured as the test framekwork, it will try to invoke both +MyHelper::Generators::TestUnitGenerator+ and +TestUnit::Generators::MyHelperGenerator+. Since none of those are defined, we can tell our generator to invoke +TestUnit::Generators::HelperGenerator+ instead, which is defined since it's a Rails generator. To do that, we just need to add: +Now, when the helper generator is invoked and TestUnit is configured as the test framework, it will try to invoke both +MyHelper::Generators::TestUnitGenerator+ and +TestUnit::Generators::MyHelperGenerator+. Since none of those are defined, we can tell our generator to invoke +TestUnit::Generators::HelperGenerator+ instead, which is defined since it's a Rails generator. To do that, we just need to add: # Search for :helper instead of :my_helper -- cgit v1.2.3 From b5fe014fdcc285f3bcb8779c4f7cfbc5a820856f Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Mon, 21 Jun 2010 00:39:32 +0200 Subject: files in the lib directory are no longer autoloaded Conceptually, the lib directory is closer 3rd party libraries than to the application itself. Thus, Rails adds it to Ruby's load path ($LOAD_PATH, $:) but it is no longer included in dependencies' load paths. To enable autoloading back put this in your config/application.rb config.load_paths += %W( #{config.root}/lib ) --- railties/lib/rails/engine/configuration.rb | 6 +++++- railties/test/application/initializers/load_path_test.rb | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'railties') diff --git a/railties/lib/rails/engine/configuration.rb b/railties/lib/rails/engine/configuration.rb index 446fe0bda9..620a723a04 100644 --- a/railties/lib/rails/engine/configuration.rb +++ b/railties/lib/rails/engine/configuration.rb @@ -20,15 +20,19 @@ module Rails paths.app.models "app/models", :eager_load => true paths.app.mailers "app/mailers", :eager_load => true paths.app.views "app/views" - paths.lib "lib", :load_path => true + + paths.lib "lib" paths.lib.tasks "lib/tasks", :glob => "**/*.rake" + paths.config "config" paths.config.initializers "config/initializers", :glob => "**/*.rb" paths.config.locales "config/locales", :glob => "*.{rb,yml}" paths.config.routes "config/routes.rb" + paths.public "public" paths.public.javascripts "public/javascripts" paths.public.stylesheets "public/stylesheets" + paths end end diff --git a/railties/test/application/initializers/load_path_test.rb b/railties/test/application/initializers/load_path_test.rb index 714d62311d..d9aac8719c 100644 --- a/railties/test/application/initializers/load_path_test.rb +++ b/railties/test/application/initializers/load_path_test.rb @@ -19,7 +19,7 @@ module ApplicationTests assert $:.include?("#{app_path}/app/models") end - test "initializing an application allows to load code on lib path inside application class definitation" do + test "initializing an application allows to load code on lib path inside application class definition" do app_file "lib/foo.rb", <<-RUBY module Foo; end RUBY @@ -60,6 +60,8 @@ module ApplicationTests add_to_config <<-RUBY config.root = "#{app_path}" + config.cache_classes = true + config.load_paths << "#{app_path}/lib" config.eager_load_paths << "#{app_path}/lib" RUBY -- cgit v1.2.3 From 746a3856782293b7b81706498ebaf58b51da294e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Mon, 21 Jun 2010 01:03:26 +0200 Subject: Remove unused webrick_server file. --- railties/lib/rails/webrick_server.rb | 156 ----------------------------------- 1 file changed, 156 deletions(-) delete mode 100644 railties/lib/rails/webrick_server.rb (limited to 'railties') diff --git a/railties/lib/rails/webrick_server.rb b/railties/lib/rails/webrick_server.rb deleted file mode 100644 index f3b74c28d3..0000000000 --- a/railties/lib/rails/webrick_server.rb +++ /dev/null @@ -1,156 +0,0 @@ -# Donated by Florian Gross - -require 'webrick' -require 'cgi' -require 'stringio' -require 'dispatcher' - -include WEBrick - -class CGI #:nodoc: - def stdinput - @stdin || $stdin - end - - def env_table - @env_table || ENV - end - - def initialize(type = "query", table = nil, stdin = nil) - @env_table, @stdin = table, stdin - - if defined?(MOD_RUBY) && !ENV.key?("GATEWAY_INTERFACE") - Apache.request.setup_cgi_env - end - - extend QueryExtension - @multipart = false - if defined?(CGI_PARAMS) - warn "do not use CGI_PARAMS and CGI_COOKIES" - @params = CGI_PARAMS.dup - @cookies = CGI_COOKIES.dup - else - initialize_query() # set @params, @cookies - end - @output_cookies = nil - @output_hidden = nil - end -end - -# A custom dispatch servlet for use with WEBrick. It dispatches requests -# (using the Rails Dispatcher) to the appropriate controller/action. By default, -# it restricts WEBrick to a managing a single Rails request at a time, but you -# can change this behavior by setting ActionController::Base.allow_concurrency -# to true. -class DispatchServlet < WEBrick::HTTPServlet::AbstractServlet - # Start the WEBrick server with the given options, mounting the - # DispatchServlet at /. - def self.dispatch(options = {}) - Socket.do_not_reverse_lookup = true # patch for OS X - - params = { :Port => options[:port].to_i, - :ServerType => options[:server_type], - :BindAddress => options[:ip] } - params[:MimeTypes] = options[:mime_types] if options[:mime_types] - - server = WEBrick::HTTPServer.new(params) - server.mount('/', DispatchServlet, options) - - trap("INT") { server.shutdown } - server.start - end - - def initialize(server, options) #:nodoc: - @server_options = options - @file_handler = WEBrick::HTTPServlet::FileHandler.new(server, options[:server_root]) - # Change to the Rails.root, since Webrick::Daemon.start does a Dir::cwd("/") - # OPTIONS['working_directory'] is an absolute path of the Rails.root, set in railties/lib/commands/servers/webrick.rb - Dir.chdir(OPTIONS['working_directory']) if defined?(OPTIONS) && File.directory?(OPTIONS['working_directory']) - super - end - - def service(req, res) #:nodoc: - unless handle_file(req, res) - unless handle_dispatch(req, res) - raise WEBrick::HTTPStatus::NotFound, "`#{req.path}' not found." - end - end - end - - def handle_file(req, res) #:nodoc: - begin - req = req.dup - path = req.path.dup - - # Add .html if the last path piece has no . in it - path << '.html' if path != '/' && (%r{(^|/)[^./]+$} =~ path) - path.gsub!('+', ' ') # Unescape + since FileHandler doesn't do so. - - req.instance_variable_set(:@path_info, path) # Set the modified path... - - @file_handler.send(:service, req, res) - return true - rescue HTTPStatus::PartialContent, HTTPStatus::NotModified => err - res.set_error(err) - return true - rescue => err - return false - end - end - - def handle_dispatch(req, res, origin = nil) #:nodoc: - data = StringIO.new - Dispatcher.dispatch( - CGI.new("query", create_env_table(req, origin), StringIO.new(req.body || "")), - ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS, - data - ) - - header, body = extract_header_and_body(data) - - set_charset(header) - assign_status(res, header) - res.cookies.concat(header.delete('set-cookie') || []) - header.each { |key, val| res[key] = val.join(", ") } - - res.body = body - return true - rescue => err - p err, err.backtrace - return false - end - - private - def create_env_table(req, origin) - env = req.meta_vars.clone - env.delete "SCRIPT_NAME" - env["QUERY_STRING"] = req.request_uri.query - env["REQUEST_URI"] = origin if origin - return env - end - - def extract_header_and_body(data) - data.rewind - data = data.read - - raw_header, body = *data.split(/^[\xd\xa]{2}/on, 2) - header = WEBrick::HTTPUtils::parse_header(raw_header) - - return header, body - end - - def set_charset(header) - ct = header["content-type"] - if ct.any? { |x| x =~ /^text\// } && ! ct.any? { |x| x =~ /charset=/ } - ch = @server_options[:charset] || "UTF-8" - ct.find { |x| x =~ /^text\// } << ("; charset=" + ch) - end - end - - def assign_status(res, header) - if /^(\d+)/ =~ header['status'][0] - res.status = $1.to_i - header.delete('status') - end - end -end -- cgit v1.2.3 From f81666698b703be69607a8ce1abb7d2347ea3667 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Mon, 21 Jun 2010 01:08:50 +0200 Subject: Alias app to build_middleware_stack for clarity. --- railties/lib/rails/application.rb | 1 + railties/lib/rails/application/finisher.rb | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'railties') diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index 8b8ef20b1f..eca6802297 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -160,6 +160,7 @@ module Rails config.middleware.build(routes) end end + alias :build_middleware_stack :app def call(env) app.call(env.reverse_merge!(env_defaults)) diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb index d7ff489336..11a3329de6 100644 --- a/railties/lib/rails/application/finisher.rb +++ b/railties/lib/rails/application/finisher.rb @@ -32,7 +32,7 @@ module Rails end initializer :build_middleware_stack do - app + build_middleware_stack end initializer :eager_load! do -- cgit v1.2.3 From b311dbb0ba2f3679a21fd7cb53b867c580e1e809 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Mon, 21 Jun 2010 01:46:24 +0200 Subject: Revert "files in the lib directory are no longer autoloaded" This patch is not consistent since it leaves similar directories in load_paths, needs more thought. This reverts commit b5fe014fdcc285f3bcb8779c4f7cfbc5a820856f. --- railties/lib/rails/engine/configuration.rb | 6 +----- railties/test/application/initializers/load_path_test.rb | 4 +--- 2 files changed, 2 insertions(+), 8 deletions(-) (limited to 'railties') diff --git a/railties/lib/rails/engine/configuration.rb b/railties/lib/rails/engine/configuration.rb index 620a723a04..446fe0bda9 100644 --- a/railties/lib/rails/engine/configuration.rb +++ b/railties/lib/rails/engine/configuration.rb @@ -20,19 +20,15 @@ module Rails paths.app.models "app/models", :eager_load => true paths.app.mailers "app/mailers", :eager_load => true paths.app.views "app/views" - - paths.lib "lib" + paths.lib "lib", :load_path => true paths.lib.tasks "lib/tasks", :glob => "**/*.rake" - paths.config "config" paths.config.initializers "config/initializers", :glob => "**/*.rb" paths.config.locales "config/locales", :glob => "*.{rb,yml}" paths.config.routes "config/routes.rb" - paths.public "public" paths.public.javascripts "public/javascripts" paths.public.stylesheets "public/stylesheets" - paths end end diff --git a/railties/test/application/initializers/load_path_test.rb b/railties/test/application/initializers/load_path_test.rb index d9aac8719c..714d62311d 100644 --- a/railties/test/application/initializers/load_path_test.rb +++ b/railties/test/application/initializers/load_path_test.rb @@ -19,7 +19,7 @@ module ApplicationTests assert $:.include?("#{app_path}/app/models") end - test "initializing an application allows to load code on lib path inside application class definition" do + test "initializing an application allows to load code on lib path inside application class definitation" do app_file "lib/foo.rb", <<-RUBY module Foo; end RUBY @@ -60,8 +60,6 @@ module ApplicationTests add_to_config <<-RUBY config.root = "#{app_path}" - config.cache_classes = true - config.load_paths << "#{app_path}/lib" config.eager_load_paths << "#{app_path}/lib" RUBY -- cgit v1.2.3 From 0da754dc5935acb720c7593fd3faaf2fa8aece1a Mon Sep 17 00:00:00 2001 From: rspeicher Date: Sun, 20 Jun 2010 21:21:44 -0400 Subject: Generators Guide: Fix another typo I introduced --- railties/guides/source/generators.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'railties') diff --git a/railties/guides/source/generators.textile b/railties/guides/source/generators.textile index f39451f243..c5b41673e1 100644 --- a/railties/guides/source/generators.textile +++ b/railties/guides/source/generators.textile @@ -33,7 +33,7 @@ $ rails generate helper --help h3. Creating Your First Generator -Since Rails 3.0, generators are built on top of "Thor":http://github.com/wycats/thor. Thor provides power options parsing and a great API for manipulating files. For instance, let's build a generator that creates an initializer file named +initializer.rb+ inside +config/initializers+. +Since Rails 3.0, generators are built on top of "Thor":http://github.com/wycats/thor. Thor provides powerful options parsing and a great API for manipulating files. For instance, let's build a generator that creates an initializer file named +initializer.rb+ inside +config/initializers+. The first step is to create a file at +RAILS_APP/lib/generators/initializer_generator.rb+ with the following content: -- cgit v1.2.3 From 9b7540bd9220333097a1ed2f00e09a4492916570 Mon Sep 17 00:00:00 2001 From: rohit Date: Mon, 21 Jun 2010 10:11:21 +0530 Subject: Guides: AS Core Extentions, minor typos fixed. --- railties/guides/source/active_support_core_extensions.textile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'railties') diff --git a/railties/guides/source/active_support_core_extensions.textile b/railties/guides/source/active_support_core_extensions.textile index cd7a183def..1ce0ed8d7b 100644 --- a/railties/guides/source/active_support_core_extensions.textile +++ b/railties/guides/source/active_support_core_extensions.textile @@ -24,7 +24,7 @@ h5. Cherry-picking a Definition The most lightweight way to get +blank?+ is to cherry-pick the file that defines it. -For every single method defined as a core extension this guide has a note that says where is such a method defined. In the case of +blank?+ the note reads: +For every single method defined as a core extension this guide has a note that says where such a method is defined. In the case of +blank?+ the note reads: NOTE: Defined in +active_support/core_ext/object/blank.rb+. @@ -124,7 +124,7 @@ NOTE: Defined in +active_support/core_ext/object/blank.rb+. h4. +duplicable?+ -A few fundamental objects in Ruby are singletons. For example, in the whole live of a program the integer 1 refers always to the same instance: +A few fundamental objects in Ruby are singletons. For example, in the whole life of a program the integer 1 refers always to the same instance: 1.object_id # => 3 -- cgit v1.2.3 From 94a7964a89efcd1b66ade39759a4cf8cb8c92266 Mon Sep 17 00:00:00 2001 From: rohit Date: Mon, 21 Jun 2010 10:16:06 +0530 Subject: Guides: AS Core Extentions, fix warning message to display correctly. --- railties/guides/source/active_support_core_extensions.textile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'railties') diff --git a/railties/guides/source/active_support_core_extensions.textile b/railties/guides/source/active_support_core_extensions.textile index 1ce0ed8d7b..82d1099814 100644 --- a/railties/guides/source/active_support_core_extensions.textile +++ b/railties/guides/source/active_support_core_extensions.textile @@ -209,8 +209,7 @@ String.singleton_class # => # String.new.singleton_class # => #> -WARNING: Fixnums and symbols have no singleton classes, +singleton_class+ -raises +TypeError+ on them. Moreover, the singleton classes of +nil+, +true+, and +false+, are +NilClass+, +TrueClass+, and +FalseClass+, respectively. +WARNING: Fixnums and symbols have no singleton classes, +singleton_class+ raises +TypeError+ on them. Moreover, the singleton classes of +nil+, +true+, and +false+, are +NilClass+, +TrueClass+, and +FalseClass+, respectively. NOTE: Defined in +active_support/core_ext/kernel/singleton_class.rb+. -- cgit v1.2.3 From eaa973fc7836f40fa73ffba5fd7e9f6c8a3dcd10 Mon Sep 17 00:00:00 2001 From: rohit Date: Mon, 21 Jun 2010 10:33:36 +0530 Subject: Guides: AS Core Extensions, minor type --- railties/guides/source/active_support_core_extensions.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'railties') diff --git a/railties/guides/source/active_support_core_extensions.textile b/railties/guides/source/active_support_core_extensions.textile index 82d1099814..0c7cdd100d 100644 --- a/railties/guides/source/active_support_core_extensions.textile +++ b/railties/guides/source/active_support_core_extensions.textile @@ -255,7 +255,7 @@ NOTE: Defined in +active_support/core_ext/object/acts_like.rb+. h4. +to_param+ -All objects in Rails respond to the method +to_param+, which is meant to return something that represents them as values in a query string, or as a URL fragments. +All objects in Rails respond to the method +to_param+, which is meant to return something that represents them as values in a query string, or as URL fragments. By default +to_param+ just calls +to_s+: -- cgit v1.2.3 From ead72b319f781ae3767a8695e3e29e9249388f7f Mon Sep 17 00:00:00 2001 From: Jeff Kreeftmeijer Date: Mon, 21 Jun 2010 00:46:23 +0200 Subject: Changed `ruby /path/to/rails myapp --dev` to `ruby /path/to/rails new myapp --dev` in the "Thor is not avalable" message. [#4915 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- railties/lib/rails/generators/base.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'railties') diff --git a/railties/lib/rails/generators/base.rb b/railties/lib/rails/generators/base.rb index bd2260fc29..67a9a6030d 100644 --- a/railties/lib/rails/generators/base.rb +++ b/railties/lib/rails/generators/base.rb @@ -3,7 +3,7 @@ begin rescue LoadError puts "Thor is not available.\nIf you ran this command from a git checkout " \ "of Rails, please make sure thor is installed,\nand run this command " \ - "as `ruby /path/to/rails myapp --dev`" + "as `ruby /path/to/rails new myapp --dev`" exit end -- cgit v1.2.3 From 23d277476a396088633d0cb2ef8d3be5c3557953 Mon Sep 17 00:00:00 2001 From: Jaime Iniesta Date: Mon, 21 Jun 2010 12:39:27 +0200 Subject: Ignore file guides/output/layout.html on W3C validations --- railties/guides/w3c_validator.rb | 1 + 1 file changed, 1 insertion(+) (limited to 'railties') diff --git a/railties/guides/w3c_validator.rb b/railties/guides/w3c_validator.rb index 49cfb984cf..4da48bf3fb 100644 --- a/railties/guides/w3c_validator.rb +++ b/railties/guides/w3c_validator.rb @@ -55,6 +55,7 @@ module RailsGuides private def guides_to_validate guides = Dir["./guides/output/*.html"] + guides.delete("./guides/output/layout.html") ENV.key?('ONLY') ? select_only(guides) : guides end -- cgit v1.2.3 From 1b369be02ffe52b9b278c41c762eedc35d52b348 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Mon, 21 Jun 2010 18:28:00 -0700 Subject: Bump rack-mount to 0.6.5 for tokenizer speedup --- railties/guides/source/initialization.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'railties') diff --git a/railties/guides/source/initialization.textile b/railties/guides/source/initialization.textile index bc3a2d0f0b..e458413b35 100644 --- a/railties/guides/source/initialization.textile +++ b/railties/guides/source/initialization.textile @@ -148,7 +148,7 @@ Here the only two gems we need are +rails+ and +sqlite3-ruby+, so it seems. This * mime-types-1.16.gem * polyglot-0.3.1.gem * rack-1.1.0.gem -* rack-mount-0.6.4.gem +* rack-mount-0.6.5.gem * rack-test-0.5.4.gem * rails-3.0.0.beta4.gem * railties-3.0.0.beta4.gem -- cgit v1.2.3 From 36d1e90e22c9841b146b67ece49d0744fa606e0c Mon Sep 17 00:00:00 2001 From: Jamison Dance Date: Tue, 22 Jun 2010 03:27:29 -0600 Subject: fixing some comma and grammar problems in the note about SQLite3 and other database configurations --- railties/guides/source/getting_started.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'railties') diff --git a/railties/guides/source/getting_started.textile b/railties/guides/source/getting_started.textile index 7b4f1ca471..6abb3ed9f4 100644 --- a/railties/guides/source/getting_started.textile +++ b/railties/guides/source/getting_started.textile @@ -227,7 +227,7 @@ development: timeout: 5000 -NOTE: In this guide we are using an SQLite3 database for data storage, this is because it is a zero configuration database that just works. Rails also supports MySQL and PostgreSQL "out of the box", and has plugins for many database systems, if you are using a database in a production environment, Rails most likely has an adapter for it. +NOTE: In this guide we are using an SQLite3 database for data storage, because it is a zero configuration database that just works. Rails also supports MySQL and PostgreSQL "out of the box", and has plugins for many database systems. If you are using a database in a production environment Rails most likely has an adapter for it. h5. Configuring a MySQL Database -- cgit v1.2.3 From 9be0b509628388a290b117e6b02df871d97f8c2d Mon Sep 17 00:00:00 2001 From: rohit Date: Tue, 22 Jun 2010 18:44:46 +0530 Subject: Added 4 tests for Rails Runner. 2 failing tests for $0 and $PROGRAM_NAME [#2244 state:open] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- railties/test/application/runner_test.rb | 49 ++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 railties/test/application/runner_test.rb (limited to 'railties') diff --git a/railties/test/application/runner_test.rb b/railties/test/application/runner_test.rb new file mode 100644 index 0000000000..d37b7649e2 --- /dev/null +++ b/railties/test/application/runner_test.rb @@ -0,0 +1,49 @@ +require 'isolation/abstract_unit' + +module ApplicationTests + class RunnerTest < Test::Unit::TestCase + include ActiveSupport::Testing::Isolation + + def setup + build_app + boot_rails + + # Lets create a model so we have something to play with + app_file "app/models/user.rb", <<-MODEL + class User + def self.count + 42 + end + end + MODEL + end + + def test_should_run_ruby_statement + assert_match "42", Dir.chdir(app_path) { `bundle exec rails runner "puts User.count"` } + end + + def test_should_run_file + app_file "script/count_users.rb", <<-SCRIPT + puts User.count + SCRIPT + + assert_match "42", Dir.chdir(app_path) { `bundle exec rails runner "script/count_users.rb"` } + end + + def test_should_set_dollar_0_to_file + app_file "script/dollar0.rb", <<-SCRIPT + puts $0 + SCRIPT + + assert_match "script/dollar0.rb", Dir.chdir(app_path) { `bundle exec rails runner "script/dollar0.rb"` } + end + + def test_should_set_dollar_program_name_to_file + app_file "script/program_name.rb", <<-SCRIPT + puts $PROGRAM_NAME + SCRIPT + + assert_match "script/program_name.rb", Dir.chdir(app_path) { `bundle exec rails runner "script/program_name.rb"` } + end + end +end -- cgit v1.2.3 From 40bf76165c392a15cd74321dd7d1cbc96c77bd27 Mon Sep 17 00:00:00 2001 From: rohit Date: Tue, 22 Jun 2010 18:45:58 +0530 Subject: Rails Runner now sets $0 and $PROGRAM_NAME to name of file being run [#2244 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- railties/lib/rails/commands/runner.rb | 1 + 1 file changed, 1 insertion(+) (limited to 'railties') diff --git a/railties/lib/rails/commands/runner.rb b/railties/lib/rails/commands/runner.rb index 278548558e..b97ff086b6 100644 --- a/railties/lib/rails/commands/runner.rb +++ b/railties/lib/rails/commands/runner.rb @@ -44,6 +44,7 @@ begin $stderr.puts "Run '#{$0} -h' for help." exit 1 elsif File.exist?(code_or_file) + $0 = code_or_file eval(File.read(code_or_file), nil, code_or_file) else eval(code_or_file) -- cgit v1.2.3 From 64987d6711747495cb874aa0f5ab827ca01b4009 Mon Sep 17 00:00:00 2001 From: Trevor Turk Date: Tue, 22 Jun 2010 11:42:35 -0500 Subject: Note that 'rails server' allows specifying mongrel, thin, etc [#4845 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- railties/lib/rails/commands/server.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'railties') diff --git a/railties/lib/rails/commands/server.rb b/railties/lib/rails/commands/server.rb index cb9b871875..9d9dd48ea9 100644 --- a/railties/lib/rails/commands/server.rb +++ b/railties/lib/rails/commands/server.rb @@ -9,7 +9,7 @@ module Rails args, options = args.dup, {} opt_parser = OptionParser.new do |opts| - opts.banner = "Usage: rails server [options]" + opts.banner = "Usage: rails server [mongrel, thin, etc] [options]" opts.on("-p", "--port=port", Integer, "Runs Rails on the specified port.", "Default: 3000") { |v| options[:Port] = v } opts.on("-b", "--binding=ip", String, -- cgit v1.2.3 From 7008911222826eef07a338bf4cab27b83fe90ce1 Mon Sep 17 00:00:00 2001 From: "Mohammed Siddick.E" Date: Wed, 23 Jun 2010 12:33:34 +0530 Subject: Patch for Namespace problem in Scaffold. [#4763 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- .../erb/scaffold/templates/_form.html.erb | 8 +- .../erb/scaffold/templates/edit.html.erb | 4 +- .../erb/scaffold/templates/index.html.erb | 14 +-- .../generators/erb/scaffold/templates/new.html.erb | 2 +- .../erb/scaffold/templates/show.html.erb | 4 +- railties/lib/rails/generators/named_base.rb | 18 +++- railties/lib/rails/generators/rails/model/USAGE | 2 +- .../rails/resource/resource_generator.rb | 5 +- .../scaffold_controller/templates/controller.rb | 54 +++++------ railties/lib/rails/generators/resource_helpers.rb | 2 +- .../generators/test_unit/model/model_generator.rb | 2 +- .../scaffold/templates/functional_test.rb | 24 ++--- .../test/generators/scaffold_generator_test.rb | 106 +++++++++++++++++++++ 13 files changed, 185 insertions(+), 60 deletions(-) (limited to 'railties') diff --git a/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb index 9b83207b3f..d12b2ff0e5 100644 --- a/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb @@ -1,10 +1,10 @@ -<%%= form_for(@<%= singular_name %>) do |f| %> - <%% if @<%= singular_name %>.errors.any? %> +<%%= form_for(@<%= singular_table_name %>) do |f| %> + <%% if @<%= singular_table_name %>.errors.any? %>
-

<%%= pluralize(@<%= singular_name %>.errors.count, "error") %> prohibited this <%= singular_name %> from being saved:

+

<%%= pluralize(@<%= singular_table_name %>.errors.count, "error") %> prohibited this <%= singular_table_name %> from being saved:

    - <%% @<%= singular_name %>.errors.full_messages.each do |msg| %> + <%% @<%= singular_table_name %>.errors.full_messages.each do |msg| %>
  • <%%= msg %>
  • <%% end %>
diff --git a/railties/lib/rails/generators/erb/scaffold/templates/edit.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/edit.html.erb index 415f820206..e58b9fbd08 100644 --- a/railties/lib/rails/generators/erb/scaffold/templates/edit.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/edit.html.erb @@ -1,6 +1,6 @@ -

Editing <%= singular_name %>

+

Editing <%= singular_table_name %>

<%%= render 'form' %> -<%%= link_to 'Show', @<%= singular_name %> %> | +<%%= link_to 'Show', @<%= singular_table_name %> %> | <%%= link_to 'Back', <%= index_helper %>_path %> diff --git a/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb index d30d306d42..4c46db4d67 100644 --- a/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb @@ -1,4 +1,4 @@ -

Listing <%= plural_name %>

+

Listing <%= plural_table_name %>

@@ -10,18 +10,18 @@ -<%% @<%= plural_name %>.each do |<%= singular_name %>| %> +<%% @<%= plural_table_name %>.each do |<%= singular_table_name %>| %> <% for attribute in attributes -%> - + <% end -%> - - - + + + <%% end %>
<%%= <%= singular_name %>.<%= attribute.name %> %><%%= <%= singular_table_name %>.<%= attribute.name %> %><%%= link_to 'Show', <%= singular_name %> %><%%= link_to 'Edit', edit_<%= singular_name %>_path(<%= singular_name %>) %><%%= link_to 'Destroy', <%= singular_name %>, :confirm => 'Are you sure?', :method => :delete %><%%= link_to 'Show', <%= singular_table_name %> %><%%= link_to 'Edit', edit_<%= singular_table_name %>_path(<%= singular_table_name %>) %><%%= link_to 'Destroy', <%= singular_table_name %>, :confirm => 'Are you sure?', :method => :delete %>

-<%%= link_to 'New <%= human_name %>', new_<%= singular_name %>_path %> +<%%= link_to 'New <%= human_name %>', new_<%= singular_table_name %>_path %> diff --git a/railties/lib/rails/generators/erb/scaffold/templates/new.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/new.html.erb index ddabc9d349..02ae4d015e 100644 --- a/railties/lib/rails/generators/erb/scaffold/templates/new.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/new.html.erb @@ -1,4 +1,4 @@ -

New <%= singular_name %>

+

New <%= singular_table_name %>

<%%= render 'form' %> diff --git a/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb index 31b8253b35..c0e5ccff1e 100644 --- a/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb @@ -3,10 +3,10 @@ <% for attribute in attributes -%>

<%= attribute.human_name %>: - <%%= @<%= singular_name %>.<%= attribute.name %> %> + <%%= @<%= singular_table_name %>.<%= attribute.name %> %>

<% end -%> -<%%= link_to 'Edit', edit_<%= singular_name %>_path(@<%= singular_name %>) %> | +<%%= link_to 'Edit', edit_<%= singular_table_name %>_path(@<%= singular_table_name %>) %> | <%%= link_to 'Back', <%= index_helper %>_path %> diff --git a/railties/lib/rails/generators/named_base.rb b/railties/lib/rails/generators/named_base.rb index 72ec2856d0..44f831e6f3 100644 --- a/railties/lib/rails/generators/named_base.rb +++ b/railties/lib/rails/generators/named_base.rb @@ -51,7 +51,23 @@ module Rails end def index_helper - uncountable? ? "#{plural_name}_index" : plural_name + uncountable? ? "#{plural_table_name}_index" : plural_table_name + end + + def singular_table_name + @singular_table_name ||= table_name.singularize + end + + def plural_table_name + @plural_table_name ||= table_name.pluralize + end + + def plural_file_name + @plural_file_name ||= file_name.pluralize + end + + def route_url + @route_url ||= class_path.collect{|dname| "/" + dname }.join('') + "/" + plural_file_name end # Tries to retrieve the application name or simple return application. diff --git a/railties/lib/rails/generators/rails/model/USAGE b/railties/lib/rails/generators/rails/model/USAGE index db98a2dd1b..67f76aad01 100644 --- a/railties/lib/rails/generators/rails/model/USAGE +++ b/railties/lib/rails/generators/rails/model/USAGE @@ -40,6 +40,6 @@ Examples: Module: app/models/admin.rb Model: app/models/admin/account.rb Test: test/unit/admin/account_test.rb - Fixtures: test/fixtures/admin_accounts.yml + Fixtures: test/fixtures/admin/accounts.yml Migration: db/migrate/XXX_add_admin_accounts.rb diff --git a/railties/lib/rails/generators/rails/resource/resource_generator.rb b/railties/lib/rails/generators/rails/resource/resource_generator.rb index 8a46708009..ee302b8aad 100644 --- a/railties/lib/rails/generators/rails/resource/resource_generator.rb +++ b/railties/lib/rails/generators/rails/resource/resource_generator.rb @@ -18,7 +18,10 @@ module Rails def add_resource_route return if options[:actions].present? - route "resource#{:s unless options[:singleton]} :#{pluralize?(file_name)}" + route_config = class_path.collect{|namespace| "namespace :#{namespace} do " }.join(" ") + route_config << "resource#{:s unless options[:singleton]} :#{pluralize?(file_name)}" + route_config << " end" * class_path.size + route route_config end protected diff --git a/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb b/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb index b5f19b6d15..84cf58d7c4 100644 --- a/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb +++ b/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb @@ -1,53 +1,53 @@ class <%= controller_class_name %>Controller < ApplicationController <% unless options[:singleton] -%> - # GET /<%= table_name %> - # GET /<%= table_name %>.xml + # GET <%= route_url %> + # GET <%= route_url %>.xml def index - @<%= table_name %> = <%= orm_class.all(class_name) %> + @<%= plural_table_name %> = <%= orm_class.all(class_name) %> respond_to do |format| format.html # index.html.erb - format.xml { render :xml => @<%= table_name %> } + format.xml { render :xml => @<%= plural_table_name %> } end end <% end -%> - # GET /<%= table_name %>/1 - # GET /<%= table_name %>/1.xml + # GET <%= route_url %>/1 + # GET <%= route_url %>/1.xml def show - @<%= file_name %> = <%= orm_class.find(class_name, "params[:id]") %> + @<%= singular_table_name %> = <%= orm_class.find(class_name, "params[:id]") %> respond_to do |format| format.html # show.html.erb - format.xml { render :xml => @<%= file_name %> } + format.xml { render :xml => @<%= singular_table_name %> } end end - # GET /<%= table_name %>/new - # GET /<%= table_name %>/new.xml + # GET <%= route_url %>/new + # GET <%= route_url %>/new.xml def new - @<%= file_name %> = <%= orm_class.build(class_name) %> + @<%= singular_table_name %> = <%= orm_class.build(class_name) %> respond_to do |format| format.html # new.html.erb - format.xml { render :xml => @<%= file_name %> } + format.xml { render :xml => @<%= singular_table_name %> } end end - # GET /<%= table_name %>/1/edit + # GET <%= route_url %>/1/edit def edit - @<%= file_name %> = <%= orm_class.find(class_name, "params[:id]") %> + @<%= singular_table_name %> = <%= orm_class.find(class_name, "params[:id]") %> end - # POST /<%= table_name %> - # POST /<%= table_name %>.xml + # POST <%= route_url %> + # POST <%= route_url %>.xml def create - @<%= file_name %> = <%= orm_class.build(class_name, "params[:#{file_name}]") %> + @<%= singular_table_name %> = <%= orm_class.build(class_name, "params[:#{singular_table_name}]") %> respond_to do |format| if @<%= orm_instance.save %> - format.html { redirect_to(@<%= file_name %>, :notice => '<%= human_name %> was successfully created.') } - format.xml { render :xml => @<%= file_name %>, :status => :created, :location => @<%= file_name %> } + format.html { redirect_to(@<%= singular_table_name %>, :notice => '<%= human_name %> was successfully created.') } + format.xml { render :xml => @<%= singular_table_name %>, :status => :created, :location => @<%= singular_table_name %> } else format.html { render :action => "new" } format.xml { render :xml => @<%= orm_instance.errors %>, :status => :unprocessable_entity } @@ -55,14 +55,14 @@ class <%= controller_class_name %>Controller < ApplicationController end end - # PUT /<%= table_name %>/1 - # PUT /<%= table_name %>/1.xml + # PUT <%= route_url %>/1 + # PUT <%= route_url %>/1.xml def update - @<%= file_name %> = <%= orm_class.find(class_name, "params[:id]") %> + @<%= singular_table_name %> = <%= orm_class.find(class_name, "params[:id]") %> respond_to do |format| - if @<%= orm_instance.update_attributes("params[:#{file_name}]") %> - format.html { redirect_to(@<%= file_name %>, :notice => '<%= human_name %> was successfully updated.') } + if @<%= orm_instance.update_attributes("params[:#{singular_table_name}]") %> + format.html { redirect_to(@<%= singular_table_name %>, :notice => '<%= human_name %> was successfully updated.') } format.xml { head :ok } else format.html { render :action => "edit" } @@ -71,10 +71,10 @@ class <%= controller_class_name %>Controller < ApplicationController end end - # DELETE /<%= table_name %>/1 - # DELETE /<%= table_name %>/1.xml + # DELETE <%= route_url %>/1 + # DELETE <%= route_url %>/1.xml def destroy - @<%= file_name %> = <%= orm_class.find(class_name, "params[:id]") %> + @<%= singular_table_name %> = <%= orm_class.find(class_name, "params[:id]") %> @<%= orm_instance.destroy %> respond_to do |format| diff --git a/railties/lib/rails/generators/resource_helpers.rb b/railties/lib/rails/generators/resource_helpers.rb index 3a98a8f9c1..829f4b200a 100644 --- a/railties/lib/rails/generators/resource_helpers.rb +++ b/railties/lib/rails/generators/resource_helpers.rb @@ -72,7 +72,7 @@ module Rails end # Initialize ORM::Generators::ActiveModel to access instance methods. - def orm_instance(name=file_name) + def orm_instance(name=singular_table_name) @orm_instance ||= @orm_class.new(name) end end diff --git a/railties/lib/rails/generators/test_unit/model/model_generator.rb b/railties/lib/rails/generators/test_unit/model/model_generator.rb index 609b815683..c1dd535dd3 100644 --- a/railties/lib/rails/generators/test_unit/model/model_generator.rb +++ b/railties/lib/rails/generators/test_unit/model/model_generator.rb @@ -16,7 +16,7 @@ module TestUnit def create_fixture_file if options[:fixture] && options[:fixture_replacement].nil? - template 'fixtures.yml', File.join('test/fixtures', "#{table_name}.yml") + template 'fixtures.yml', File.join('test/fixtures', class_path, "#{plural_file_name}.yml") end end end diff --git a/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb b/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb index d5d3d6d5cd..957ebaa522 100644 --- a/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb +++ b/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb @@ -2,7 +2,7 @@ require 'test_helper' class <%= controller_class_name %>ControllerTest < ActionController::TestCase setup do - @<%= file_name %> = <%= table_name %>(:one) + @<%= singular_table_name %> = <%= table_name %>(:one) end <% unless options[:singleton] -%> @@ -18,32 +18,32 @@ class <%= controller_class_name %>ControllerTest < ActionController::TestCase assert_response :success end - test "should create <%= file_name %>" do + test "should create <%= singular_table_name %>" do assert_difference('<%= class_name %>.count') do - post :create, :<%= file_name %> => @<%= file_name %>.attributes + post :create, :<%= singular_table_name %> => @<%= singular_table_name %>.attributes end - assert_redirected_to <%= file_name %>_path(assigns(:<%= file_name %>)) + assert_redirected_to <%= singular_table_name %>_path(assigns(:<%= singular_table_name %>)) end - test "should show <%= file_name %>" do - get :show, :id => @<%= file_name %>.to_param + test "should show <%= singular_table_name %>" do + get :show, :id => @<%= singular_table_name %>.to_param assert_response :success end test "should get edit" do - get :edit, :id => @<%= file_name %>.to_param + get :edit, :id => @<%= singular_table_name %>.to_param assert_response :success end - test "should update <%= file_name %>" do - put :update, :id => @<%= file_name %>.to_param, :<%= file_name %> => @<%= file_name %>.attributes - assert_redirected_to <%= file_name %>_path(assigns(:<%= file_name %>)) + test "should update <%= singular_table_name %>" do + put :update, :id => @<%= singular_table_name %>.to_param, :<%= singular_table_name %> => @<%= singular_table_name %>.attributes + assert_redirected_to <%= singular_table_name %>_path(assigns(:<%= singular_table_name %>)) end - test "should destroy <%= file_name %>" do + test "should destroy <%= singular_table_name %>" do assert_difference('<%= class_name %>.count', -1) do - delete :destroy, :id => @<%= file_name %>.to_param + delete :destroy, :id => @<%= singular_table_name %>.to_param end assert_redirected_to <%= index_helper %>_path diff --git a/railties/test/generators/scaffold_generator_test.rb b/railties/test/generators/scaffold_generator_test.rb index e8e622fe5c..ea469cb3c8 100644 --- a/railties/test/generators/scaffold_generator_test.rb +++ b/railties/test/generators/scaffold_generator_test.rb @@ -110,4 +110,110 @@ class ScaffoldGeneratorTest < Rails::Generators::TestCase # Stylesheets (should not be removed) assert_file "public/stylesheets/scaffold.css" end + + def test_scaffold_with_namespace_on_invoke + run_generator [ "admin/role", "name:string", "description:string" ] + + # Model + assert_file "app/models/admin.rb", /module Admin/ + assert_file "app/models/admin/role.rb", /class Admin::Role < ActiveRecord::Base/ + assert_file "test/unit/admin/role_test.rb", /class Admin::RoleTest < ActiveSupport::TestCase/ + assert_file "test/fixtures/admin/roles.yml" + assert_migration "db/migrate/create_admin_roles.rb" + + # Route + assert_file "config/routes.rb" do |route| + assert_match /namespace :admin do resources :roles end$/, route + end + + # Controller + assert_file "app/controllers/admin/roles_controller.rb" do |content| + assert_match /class Admin::RolesController < ApplicationController/, content + + assert_instance_method :index, content do |m| + assert_match /@admin_roles = Admin::Role\.all/, m + end + + assert_instance_method :show, content do |m| + assert_match /@admin_role = Admin::Role\.find\(params\[:id\]\)/, m + end + + assert_instance_method :new, content do |m| + assert_match /@admin_role = Admin::Role\.new/, m + end + + assert_instance_method :edit, content do |m| + assert_match /@admin_role = Admin::Role\.find\(params\[:id\]\)/, m + end + + assert_instance_method :create, content do |m| + assert_match /@admin_role = Admin::Role\.new\(params\[:admin_role\]\)/, m + assert_match /@admin_role\.save/, m + assert_match /@admin_role\.errors/, m + end + + assert_instance_method :update, content do |m| + assert_match /@admin_role = Admin::Role\.find\(params\[:id\]\)/, m + assert_match /@admin_role\.update_attributes\(params\[:admin_role\]\)/, m + assert_match /@admin_role\.errors/, m + end + + assert_instance_method :destroy, content do |m| + assert_match /@admin_role = Admin::Role\.find\(params\[:id\]\)/, m + assert_match /@admin_role\.destroy/, m + end + end + + assert_file "test/functional/admin/roles_controller_test.rb", + /class Admin::RolesControllerTest < ActionController::TestCase/ + + # Views + %w( + index + edit + new + show + _form + ).each { |view| assert_file "app/views/admin/roles/#{view}.html.erb" } + assert_no_file "app/views/layouts/admin/roles.html.erb" + + # Helpers + assert_file "app/helpers/admin/roles_helper.rb" + assert_file "test/unit/helpers/admin/roles_helper_test.rb" + + # Stylesheets + assert_file "public/stylesheets/scaffold.css" + end + + def test_scaffold_with_namespace_on_revoke + run_generator [ "admin/role", "name:string", "description:string" ] + run_generator [ "admin/role" ], :behavior => :revoke + + # Model + assert_file "app/models/admin.rb" # ( should not be remove ) + assert_no_file "app/models/admin/role.rb" + assert_no_file "test/unit/admin/role_test.rb" + assert_no_file "test/fixtures/admin/roles.yml" + assert_no_migration "db/migrate/create_admin_roles.rb" + + # Route + assert_file "config/routes.rb" do |route| + assert_no_match /namespace :admin do resources :roles end$/, route + end + + # Controller + assert_no_file "app/controllers/admin/roles_controller.rb" + assert_no_file "test/functional/admin/roles_controller_test.rb" + + # Views + assert_no_file "app/views/admin/roles" + assert_no_file "app/views/layouts/admin/roles.html.erb" + + # Helpers + assert_no_file "app/helpers/admin/roles_helper.rb" + assert_no_file "test/unit/helpers/admin/roles_helper_test.rb" + + # Stylesheets (should not be removed) + assert_file "public/stylesheets/scaffold.css" + end end -- cgit v1.2.3 From 3ac5a5339790212763e0432d5aa243016520aa80 Mon Sep 17 00:00:00 2001 From: rohit Date: Wed, 23 Jun 2010 18:22:02 +0530 Subject: Guides: replace reference to hpricot with nokogiri [#3290 state:resolved] --- railties/guides/source/rails_application_templates.textile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'railties') diff --git a/railties/guides/source/rails_application_templates.textile b/railties/guides/source/rails_application_templates.textile index 1af6f56957..1bf9cfec33 100644 --- a/railties/guides/source/rails_application_templates.textile +++ b/railties/guides/source/rails_application_templates.textile @@ -51,11 +51,11 @@ h4. gem(name, options = {}) Adds a +config.gem+ entry for the supplied gem to the generated application’s +config/environment.rb+. -For example, if your application depends on the gems +bj+ and +hpricot+ : +For example, if your application depends on the gems +bj+ and +nokogiri+ : gem "bj" -gem "hpricot", :version => '0.6', :source => "http://code.whytheluckystiff.net" +gem "nokogiri" Please note that this will NOT install the gems for you. So you may want to run the +rake gems:install+ task too : -- cgit v1.2.3 From 6f83a5036d8a9c3f8ed74755ff6d42bc3f6e9982 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Tue, 22 Jun 2010 23:17:20 +0200 Subject: renames load_(once_)paths to autoload_(once_)paths in dependencies and config --- railties/CHANGELOG | 3 +++ railties/lib/rails/application.rb | 4 ++-- railties/lib/rails/application/finisher.rb | 10 +++++----- railties/lib/rails/engine.rb | 16 ++++++++-------- railties/lib/rails/engine/configuration.rb | 10 +++++----- .../generators/rails/app/templates/config/application.rb | 2 +- railties/test/generators/actions_test.rb | 6 +++--- 7 files changed, 27 insertions(+), 24 deletions(-) (limited to 'railties') diff --git a/railties/CHANGELOG b/railties/CHANGELOG index c33a4d11dd..61d84e104a 100644 --- a/railties/CHANGELOG +++ b/railties/CHANGELOG @@ -1,6 +1,9 @@ *Rails 3.0.0 [Release Candidate] (unreleased)* +* config.load_(once_)paths in config/application.rb got renamed to config.autoload_(once_)paths. [fxn] + * Abort generation/booting on Ruby 1.9.1. [fxn] + * Made the rails command work even when you're in a subdirectory [Chad Fowler] diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index eca6802297..aabe86715c 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -67,7 +67,7 @@ module Rails raise "You cannot have more than one Rails::Application" if Rails.application super Rails.application = base.instance - Rails.application.add_lib_to_load_paths! + Rails.application.add_lib_to_load_path! ActiveSupport.run_load_hooks(:before_configuration, base.instance) end @@ -97,7 +97,7 @@ module Rails # are changing config.root inside your application definition or having a custom # Rails application, you will need to add lib to $LOAD_PATH on your own in case # you need to load files in lib/ during the application configuration as well. - def add_lib_to_load_paths! #:nodoc: + def add_lib_to_load_path! #:nodoc: path = config.root.join('lib').to_s $LOAD_PATH.unshift(path) if File.exists?(path) end diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb index 11a3329de6..855467227b 100644 --- a/railties/lib/rails/application/finisher.rb +++ b/railties/lib/rails/application/finisher.rb @@ -7,14 +7,14 @@ module Rails config.generators.templates.unshift(*paths.lib.templates.to_a) end - initializer :ensure_load_once_paths_as_subset do - extra = ActiveSupport::Dependencies.load_once_paths - - ActiveSupport::Dependencies.load_paths + initializer :ensure_autoload_once_paths_as_subset do + extra = ActiveSupport::Dependencies.autoload_once_paths - + ActiveSupport::Dependencies.autoload_paths unless extra.empty? abort <<-end_error - load_once_paths must be a subset of the load_paths. - Extra items in load_once_paths: #{extra * ','} + autoload_once_paths must be a subset of the autoload_paths. + Extra items in autoload_once_paths: #{extra * ','} end_error end end diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index cdb00a4eff..0a3f21fb1b 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -32,14 +32,14 @@ module Rails # == Configuration # # Besides the Railtie configuration which is shared across the application, in a - # Rails::Engine you can access load_paths, eager_load_paths and load_once_paths, + # Rails::Engine you can access autoload_paths, eager_load_paths and autoload_once_paths, # which differently from a Railtie, are scoped to the current Engine. # # Example: # # class MyEngine < Rails::Engine # # Add a load path for this specific Engine - # config.load_paths << File.expand_path("../lib/some/path", __FILE__) + # config.autoload_paths << File.expand_path("../lib/some/path", __FILE__) # # initializer "my_engine.add_middleware" do |app| # app.middleware.use MyEngine::Middleware @@ -142,7 +142,7 @@ module Rails # Add configured load paths to ruby load paths and remove duplicates. initializer :set_load_path, :before => :bootstrap_hook do - config.load_paths.reverse_each do |path| + config.autoload_paths.reverse_each do |path| $LOAD_PATH.unshift(path) if File.directory?(path) end $LOAD_PATH.uniq! @@ -154,17 +154,17 @@ module Rails # This needs to be an initializer, since it needs to run once # per engine and get the engine as a block parameter initializer :set_autoload_paths, :before => :bootstrap_hook do |app| - ActiveSupport::Dependencies.load_paths.unshift(*config.load_paths) + ActiveSupport::Dependencies.autoload_paths.unshift(*config.autoload_paths) if reloadable?(app) - ActiveSupport::Dependencies.load_once_paths.unshift(*config.load_once_paths) + ActiveSupport::Dependencies.autoload_once_paths.unshift(*config.autoload_once_paths) else - ActiveSupport::Dependencies.load_once_paths.unshift(*config.load_paths) + ActiveSupport::Dependencies.autoload_once_paths.unshift(*config.autoload_paths) end # Freeze so future modifications will fail rather than do nothing mysteriously - config.load_paths.freeze - config.load_once_paths.freeze + config.autoload_paths.freeze + config.autoload_once_paths.freeze end initializer :add_routing_paths do |app| diff --git a/railties/lib/rails/engine/configuration.rb b/railties/lib/rails/engine/configuration.rb index 446fe0bda9..4e27180f1e 100644 --- a/railties/lib/rails/engine/configuration.rb +++ b/railties/lib/rails/engine/configuration.rb @@ -4,7 +4,7 @@ module Rails class Engine class Configuration < ::Rails::Railtie::Configuration attr_reader :root - attr_writer :eager_load_paths, :load_once_paths, :load_paths + attr_writer :eager_load_paths, :autoload_once_paths, :autoload_paths def initialize(root=nil) super() @@ -41,12 +41,12 @@ module Rails @eager_load_paths ||= paths.eager_load end - def load_once_paths - @load_once_paths ||= paths.load_once + def autoload_once_paths + @autoload_once_paths ||= paths.load_once end - def load_paths - @load_paths ||= paths.load_paths + def autoload_paths + @autoload_paths ||= paths.load_paths end end end 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 0066e2b0c2..031466cb86 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/application.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/application.rb @@ -22,7 +22,7 @@ module <%= app_const_base %> # -- all .rb files in that directory are automatically loaded. # Add additional load paths for your own custom dirs - # config.load_paths += %W( #{config.root}/extras ) + # config.autoload_paths += %W( #{config.root}/extras ) # Only load the plugins named here, in the order given (default is alphabetical). # :all can be used as a placeholder for all plugins not explicitly named diff --git a/railties/test/generators/actions_test.rb b/railties/test/generators/actions_test.rb index 65fbf61902..0472ca73a8 100644 --- a/railties/test/generators/actions_test.rb +++ b/railties/test/generators/actions_test.rb @@ -130,9 +130,9 @@ class ActionsTest < Rails::Generators::TestCase def test_environment_should_include_data_in_environment_initializer_block run_generator - load_paths = 'config.load_paths += %w["#{Rails.root}/app/extras"]' - action :environment, load_paths - assert_file 'config/application.rb', /#{Regexp.escape(load_paths)}/ + autoload_paths = 'config.autoload_paths += %w["#{Rails.root}/app/extras"]' + action :environment, autoload_paths + assert_file 'config/application.rb', /#{Regexp.escape(autoload_paths)}/ end def test_environment_with_block_should_include_block_contents_in_environment_initializer_block -- cgit v1.2.3 From 0b3dd5718ca4de5773d9e54e6b3b51f7ba83823c Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Thu, 24 Jun 2010 01:55:58 -0700 Subject: Array#sample now exists, so test for #forty_two instead --- railties/test/application/initializers/frameworks_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'railties') diff --git a/railties/test/application/initializers/frameworks_test.rb b/railties/test/application/initializers/frameworks_test.rb index 35ea2729d3..604c50ec2d 100644 --- a/railties/test/application/initializers/frameworks_test.rb +++ b/railties/test/application/initializers/frameworks_test.rb @@ -57,7 +57,7 @@ module ApplicationTests Dir.chdir("#{app_path}/app") do require "#{app_path}/config/environment" - assert_raises(NoMethodError) { [1,2,3].sample } + assert_raises(NoMethodError) { [1,2,3].forty_two } end end -- cgit v1.2.3 From 60ab9255f0cb09ee5d2891878f715f301ad7a213 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Thu, 24 Jun 2010 01:56:16 -0700 Subject: Don't halt railties tests on failures --- railties/Rakefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'railties') diff --git a/railties/Rakefile b/railties/Rakefile index bf19961b59..ddc872e18b 100644 --- a/railties/Rakefile +++ b/railties/Rakefile @@ -18,11 +18,11 @@ task :test => 'test:isolated' namespace :test do task :isolated do dir = ENV["TEST_DIR"] || "**" - Dir["test/#{dir}/*_test.rb"].all? do |file| + Dir["test/#{dir}/*_test.rb"].each do |file| next true if file.include?("fixtures") ruby = File.join(*RbConfig::CONFIG.values_at('bindir', 'RUBY_INSTALL_NAME')) system(ruby, '-Itest', "-I#{File.dirname(__FILE__)}/../activesupport/lib", file) - end or raise "Failures" + end end end -- cgit v1.2.3 From cdb8609c64ed7db7ea91cdcd4bcb4b400f7dfe07 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Thu, 24 Jun 2010 01:37:58 -0700 Subject: Speed up boot by tsorting as infrequently as possible --- railties/lib/rails/application.rb | 2 +- railties/lib/rails/initializable.rb | 9 ++------- railties/test/railties/engine_test.rb | 2 +- 3 files changed, 4 insertions(+), 9 deletions(-) (limited to 'railties') diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index aabe86715c..5813c5757d 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -178,7 +178,7 @@ module Rails railties.all { |r| initializers += r.initializers } initializers += super initializers += Finisher.initializers_for(self) - initializers + Collection.new(initializers) end protected diff --git a/railties/lib/rails/initializable.rb b/railties/lib/rails/initializable.rb index 9a82e051e7..78f9eaf393 100644 --- a/railties/lib/rails/initializable.rb +++ b/railties/lib/rails/initializable.rb @@ -39,11 +39,6 @@ module Rails select { |i| i.before == initializer.name || i.name == initializer.after }.each(&block) end - def initialize(initializers = []) - super(initializers) - replace(tsort) - end - def +(other) Collection.new(to_a + other.to_a) end @@ -51,7 +46,7 @@ module Rails def run_initializers(*args) return if instance_variable_defined?(:@ran) - initializers.each do |initializer| + initializers.tsort.each do |initializer| initializer.run(*args) end @ran = true @@ -94,4 +89,4 @@ module Rails end end end -end \ No newline at end of file +end diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb index b3f65fd00d..3fe01e543c 100644 --- a/railties/test/railties/engine_test.rb +++ b/railties/test/railties/engine_test.rb @@ -41,7 +41,7 @@ module RailtiesTest boot_rails - initializers = Rails.application.initializers + initializers = Rails.application.initializers.tsort index = initializers.index { |i| i.name == "dummy_initializer" } selection = initializers[(index-3)..(index)].map(&:name).map(&:to_s) -- cgit v1.2.3 From 9f7874ac419f626a6a5157c757669a8b16770ae4 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Thu, 24 Jun 2010 02:13:08 -0700 Subject: Move Collection responsibility from application to initializable --- railties/lib/rails/application.rb | 2 +- railties/lib/rails/initializable.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'railties') diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index 5813c5757d..aabe86715c 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -178,7 +178,7 @@ module Rails railties.all { |r| initializers += r.initializers } initializers += super initializers += Finisher.initializers_for(self) - Collection.new(initializers) + initializers end protected diff --git a/railties/lib/rails/initializable.rb b/railties/lib/rails/initializable.rb index 78f9eaf393..46b3a02b22 100644 --- a/railties/lib/rails/initializable.rb +++ b/railties/lib/rails/initializable.rb @@ -58,7 +58,7 @@ module Rails module ClassMethods def initializers - @initializers ||= [] + @initializers ||= Collection.new end def initializers_chain -- cgit v1.2.3 From 5eb3b4d9a78268753d009404810619cf93cf6581 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Thu, 24 Jun 2010 02:16:59 -0700 Subject: Fix initializable tests --- railties/lib/rails/initializable.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'railties') diff --git a/railties/lib/rails/initializable.rb b/railties/lib/rails/initializable.rb index 46b3a02b22..fba3ad2c85 100644 --- a/railties/lib/rails/initializable.rb +++ b/railties/lib/rails/initializable.rb @@ -82,7 +82,7 @@ module Rails def run_initializers(*args) return if @ran - initializers_chain.each do |initializer| + initializers_chain.tsort.each do |initializer| instance_exec(*args, &initializer.block) end @ran = true -- cgit v1.2.3 From e061a12a156791c35bba092263ad216b1b938502 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 24 Jun 2010 11:39:37 +0200 Subject: Remove run_initializers from class methods. --- railties/lib/rails/initializable.rb | 8 -------- railties/test/initializable_test.rb | 39 +++++++++++++------------------------ 2 files changed, 14 insertions(+), 33 deletions(-) (limited to 'railties') diff --git a/railties/lib/rails/initializable.rb b/railties/lib/rails/initializable.rb index fba3ad2c85..686a2dc0cb 100644 --- a/railties/lib/rails/initializable.rb +++ b/railties/lib/rails/initializable.rb @@ -79,14 +79,6 @@ module Rails opts[:after] ||= initializers.last.name unless initializers.empty? || initializers.find { |i| i.name == opts[:before] } initializers << Initializer.new(name, nil, opts, &blk) end - - def run_initializers(*args) - return if @ran - initializers_chain.tsort.each do |initializer| - instance_exec(*args, &initializer.block) - end - @ran = true - end end end end diff --git a/railties/test/initializable_test.rb b/railties/test/initializable_test.rb index 74301a5dc5..72c35879c5 100644 --- a/railties/test/initializable_test.rb +++ b/railties/test/initializable_test.rb @@ -5,10 +5,7 @@ module InitializableTests class Foo include Rails::Initializable - - class << self - attr_accessor :foo, :bar - end + attr_accessor :foo, :bar initializer :start do @foo ||= 0 @@ -158,30 +155,22 @@ module InitializableTests include ActiveSupport::Testing::Isolation test "initializers run" do - Foo.run_initializers - assert_equal 1, Foo.foo + foo = Foo.new + foo.run_initializers + assert_equal 1, foo.foo end test "initializers are inherited" do - Bar.run_initializers - assert_equal [1, 1], [Bar.foo, Bar.bar] + bar = Bar.new + bar.run_initializers + assert_equal [1, 1], [bar.foo, bar.bar] end test "initializers only get run once" do - Foo.run_initializers - Foo.run_initializers - assert_equal 1, Foo.foo - end - - test "running initializers on children does not effect the parent" do - Bar.run_initializers - assert_nil Foo.foo - assert_nil Foo.bar - end - - test "initializing with modules" do - Word.run_initializers - assert_equal "bird", $word + foo = Foo.new + foo.run_initializers + foo.run_initializers + assert_equal 1, foo.foo end test "creating initializer without a block raises an error" do @@ -198,19 +187,19 @@ module InitializableTests class BeforeAfter < ActiveSupport::TestCase test "running on parent" do $arr = [] - Parent.run_initializers + Parent.new.run_initializers assert_equal [5, 1, 2], $arr end test "running on child" do $arr = [] - Child.run_initializers + Child.new.run_initializers assert_equal [5, 3, 1, 4, 2], $arr end test "handles dependencies introduced before all initializers are loaded" do $arr = [] - Interdependent::Application.run_initializers + Interdependent::Application.new.run_initializers assert_equal [1, 2, 3, 4], $arr end end -- cgit v1.2.3 From 6788db824ab732b13493a9d702dd8fb89fa153c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 24 Jun 2010 13:23:43 +0200 Subject: Move Rails::LogSubscriber to ActiveSupport::LogSubscriber, allowing frameworks like ActiveRecord and ActiveResource to log outsude Rails::Application [#4816 state:resolved] --- railties/lib/rails.rb | 1 - railties/lib/rails/application/configuration.rb | 2 +- railties/lib/rails/log_subscriber.rb | 115 --------------------- railties/lib/rails/log_subscriber/test_helper.rb | 97 ------------------ railties/lib/rails/rack/logger.rb | 24 ++--- railties/lib/rails/railtie.rb | 34 +------ railties/test/log_subscriber_test.rb | 123 ----------------------- 7 files changed, 14 insertions(+), 382 deletions(-) delete mode 100644 railties/lib/rails/log_subscriber.rb delete mode 100644 railties/lib/rails/log_subscriber/test_helper.rb delete mode 100644 railties/test/log_subscriber_test.rb (limited to 'railties') diff --git a/railties/lib/rails.rb b/railties/lib/rails.rb index ed66f493e6..bbf28a8c08 100644 --- a/railties/lib/rails.rb +++ b/railties/lib/rails.rb @@ -9,7 +9,6 @@ require 'active_support/core_ext/logger' require 'rails/application' require 'rails/version' require 'rails/deprecation' -require 'rails/log_subscriber' require 'active_support/railtie' require 'action_dispatch/railtie' diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index 25e54e9dce..e3165b2d4c 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -110,7 +110,7 @@ module Rails def colorize_logging=(val) @colorize_logging = val - Rails::LogSubscriber.colorize_logging = val + ActiveSupport::LogSubscriber.colorize_logging = val self.generators.colorize_logging = val end diff --git a/railties/lib/rails/log_subscriber.rb b/railties/lib/rails/log_subscriber.rb deleted file mode 100644 index a30701d4d5..0000000000 --- a/railties/lib/rails/log_subscriber.rb +++ /dev/null @@ -1,115 +0,0 @@ -require 'active_support/core_ext/class/inheritable_attributes' -require 'active_support/notifications' - -module Rails - # Rails::LogSubscriber is an object set to consume ActiveSupport::Notifications - # on initialization with solely purpose of logging. The log subscriber dispatches - # notifications to a regirested object based on its given namespace. - # - # An example would be Active Record log subscriber responsible for logging queries: - # - # module ActiveRecord - # class Railtie - # class LogSubscriber < Rails::LogSubscriber - # def sql(event) - # "#{event.payload[:name]} (#{event.duration}) #{event.payload[:sql]}" - # end - # end - # end - # end - # - # It's finally registed as: - # - # Rails::LogSubscriber.add :active_record, ActiveRecord::Railtie::LogSubscriber.new - # - # So whenever a "sql.active_record" notification arrive to Rails::LogSubscriber, - # it will properly dispatch the event (ActiveSupport::Notifications::Event) to - # the sql method. - # - # This is useful because it avoids spanning several log subscribers just for logging - # purposes(which slows down the main thread). Besides of providing a centralized - # facility on top of Rails.logger. - # - # Log subscriber also has some helpers to deal with logging and automatically flushes - # all logs when the request finishes (via action_dispatch.callback notification). - class LogSubscriber - mattr_accessor :colorize_logging - self.colorize_logging = true - - # Embed in a String to clear all previous ANSI sequences. - CLEAR = "\e[0m" - BOLD = "\e[1m" - - # Colors - BLACK = "\e[30m" - RED = "\e[31m" - GREEN = "\e[32m" - YELLOW = "\e[33m" - BLUE = "\e[34m" - MAGENTA = "\e[35m" - CYAN = "\e[36m" - WHITE = "\e[37m" - - def self.add(namespace, log_subscriber, notifier = ActiveSupport::Notifications) - log_subscribers << log_subscriber - @flushable_loggers = nil - - log_subscriber.public_methods(false).each do |event| - notifier.subscribe("#{event}.#{namespace}") do |*args| - next if log_subscriber.logger.nil? - - begin - log_subscriber.send(event, ActiveSupport::Notifications::Event.new(*args)) - rescue Exception => e - Rails.logger.error "Could not log #{args[0].inspect} event. #{e.class}: #{e.message}" - end - end - end - end - - def self.log_subscribers - @log_subscribers ||= [] - end - - def self.flushable_loggers - @flushable_loggers ||= begin - loggers = log_subscribers.map(&:logger) - loggers.uniq! - loggers.select { |l| l.respond_to?(:flush) } - end - end - - # Flush all log_subscribers' logger. - def self.flush_all! - flushable_loggers.each(&:flush) - end - - # By default, we use the Rails.logger for logging. - def logger - Rails.logger - end - - protected - - %w(info debug warn error fatal unknown).each do |level| - class_eval <<-METHOD, __FILE__, __LINE__ + 1 - def #{level}(*args, &block) - return unless logger - logger.#{level}(*args, &block) - end - METHOD - end - - # Set color by using a string or one of the defined constants. If a third - # option is set to true, it also adds bold to the string. This is based - # on Highline implementation and it automatically appends CLEAR to the end - # of the returned String. - # - def color(text, color, bold=false) - return text unless colorize_logging - color = self.class.const_get(color.to_s.upcase) if color.is_a?(Symbol) - bold = bold ? BOLD : "" - "#{bold}#{color}#{text}#{CLEAR}" - end - end -end diff --git a/railties/lib/rails/log_subscriber/test_helper.rb b/railties/lib/rails/log_subscriber/test_helper.rb deleted file mode 100644 index 9b7b0738cd..0000000000 --- a/railties/lib/rails/log_subscriber/test_helper.rb +++ /dev/null @@ -1,97 +0,0 @@ -require 'rails/log_subscriber' - -module Rails - class LogSubscriber - # Provides some helpers to deal with testing log subscribers by setting up - # notifications. Take for instance Active Record subscriber tests: - # - # class SyncLogSubscriberTest < ActiveSupport::TestCase - # include Rails::LogSubscriber::TestHelper - # Rails::LogSubscriber.add(:active_record, ActiveRecord::Railties::LogSubscriber.new) - # - # def test_basic_query_logging - # Developer.all - # wait - # assert_equal 1, @logger.logged(:debug).size - # assert_match /Developer Load/, @logger.logged(:debug).last - # assert_match /SELECT \* FROM "developers"/, @logger.logged(:debug).last - # end - # - # class SyncLogSubscriberTest < ActiveSupport::TestCase - # include Rails::LogSubscriber::SyncTestHelper - # include LogSubscriberTest - # end - # - # class AsyncLogSubscriberTest < ActiveSupport::TestCase - # include Rails::LogSubscriber::AsyncTestHelper - # include LogSubscriberTest - # end - # end - # - # All you need to do is to ensure that your log subscriber is added to Rails::Subscriber, - # as in the second line of the code above. The test helpers is reponsible for setting - # up the queue, subscriptions and turning colors in logs off. - # - # The messages are available in the @logger instance, which is a logger with limited - # powers (it actually do not send anything to your output), and you can collect them - # doing @logger.logged(level), where level is the level used in logging, like info, - # debug, warn and so on. - # - module TestHelper - def setup - @logger = MockLogger.new - @notifier = ActiveSupport::Notifications::Notifier.new(queue) - - Rails::LogSubscriber.colorize_logging = false - - set_logger(@logger) - ActiveSupport::Notifications.notifier = @notifier - end - - def teardown - set_logger(nil) - ActiveSupport::Notifications.notifier = nil - end - - class MockLogger - attr_reader :flush_count - - def initialize - @flush_count = 0 - @logged = Hash.new { |h,k| h[k] = [] } - end - - def method_missing(level, message) - @logged[level] << message - end - - def logged(level) - @logged[level].compact.map { |l| l.to_s.strip } - end - - def flush - @flush_count += 1 - end - end - - # Wait notifications to be published. - def wait - @notifier.wait - end - - # Overwrite if you use another logger in your log subscriber: - # - # def logger - # ActiveRecord::Base.logger = @logger - # end - # - def set_logger(logger) - Rails.logger = logger - end - - def queue - ActiveSupport::Notifications::Fanout.new - end - end - end -end \ No newline at end of file diff --git a/railties/lib/rails/rack/logger.rb b/railties/lib/rails/rack/logger.rb index 73e9af3b41..b3dc1f894c 100644 --- a/railties/lib/rails/rack/logger.rb +++ b/railties/lib/rails/rack/logger.rb @@ -1,10 +1,9 @@ -require 'rails/log_subscriber' require 'active_support/core_ext/time/conversions' module Rails module Rack # Log the request started and flush all loggers after it. - class Logger < Rails::LogSubscriber + class Logger < ActiveSupport::LogSubscriber def initialize(app) @app = app end @@ -16,20 +15,19 @@ module Rails after_dispatch(env) end - protected + protected - def before_dispatch(env) - request = ActionDispatch::Request.new(env) - path = request.fullpath + def before_dispatch(env) + request = ActionDispatch::Request.new(env) + path = request.fullpath - info "\n\nStarted #{env["REQUEST_METHOD"]} \"#{path}\" " \ - "for #{request.ip} at #{Time.now.to_default_s}" - end - - def after_dispatch(env) - Rails::LogSubscriber.flush_all! - end + info "\n\nStarted #{env["REQUEST_METHOD"]} \"#{path}\" " \ + "for #{request.ip} at #{Time.now.to_default_s}" + end + def after_dispatch(env) + ActiveSupport::LogSubscriber.flush_all! + end end end end diff --git a/railties/lib/rails/railtie.rb b/railties/lib/rails/railtie.rb index ad776933f2..dbdbfea509 100644 --- a/railties/lib/rails/railtie.rb +++ b/railties/lib/rails/railtie.rb @@ -114,36 +114,6 @@ module Rails # end # end # - # == Adding your subscriber - # - # Since version 3.0, Rails ships with a notification system which is used for several - # purposes, including logging. If you are sending notifications in your Railtie, you may - # want to add a subscriber to consume such notifications for logging purposes. - # - # The subscriber is added under the railtie_name namespace and only consumes notifications - # under the given namespace. For example, let's suppose your railtie is publishing the - # following "something_expensive" instrumentation: - # - # ActiveSupport::Notifications.instrument "my_railtie.something_expensive" do - # # something expensive - # end - # - # You can log this instrumentation with your own Rails::Subscriber: - # - # class MyRailtie::Subscriber < Rails::Subscriber - # def something_expensive(event) - # info("Something expensive took %.1fms" % event.duration) - # end - # end - # - # By registering it: - # - # class MyRailtie < Railtie - # subscriber :my_gem, MyRailtie::Subscriber.new - # end - # - # Take a look in Rails::Subscriber docs for more information. - # # == Application, Plugin and Engine # # A Rails::Engine is nothing more than a Railtie with some initializers already set. @@ -176,8 +146,8 @@ module Rails ActiveSupport::Deprecation.warn "railtie_name is deprecated and has no effect", caller end - def log_subscriber(name, log_subscriber) - Rails::LogSubscriber.add(name, log_subscriber) + def log_subscriber(*) + ActiveSupport::Deprecation.warn "log_subscriber is deprecated and has no effect", caller end def rake_tasks(&blk) diff --git a/railties/test/log_subscriber_test.rb b/railties/test/log_subscriber_test.rb deleted file mode 100644 index a3a755ae62..0000000000 --- a/railties/test/log_subscriber_test.rb +++ /dev/null @@ -1,123 +0,0 @@ -require 'abstract_unit' -require 'rails/log_subscriber/test_helper' - -class MyLogSubscriber < Rails::LogSubscriber - attr_reader :event - - def some_event(event) - @event = event - info event.name - end - - def foo(event) - debug "debug" - info "info" - warn "warn" - end - - def bar(event) - info "#{color("cool", :red)}, #{color("isn't it?", :blue, true)}" - end - - def puke(event) - raise "puke" - end -end - -class SyncLogSubscriberTest < ActiveSupport::TestCase - include Rails::LogSubscriber::TestHelper - - def setup - super - @log_subscriber = MyLogSubscriber.new - end - - def teardown - super - Rails::LogSubscriber.log_subscribers.clear - end - - def instrument(*args, &block) - ActiveSupport::Notifications.instrument(*args, &block) - end - - def test_proxies_method_to_rails_logger - @log_subscriber.foo(nil) - assert_equal %w(debug), @logger.logged(:debug) - assert_equal %w(info), @logger.logged(:info) - assert_equal %w(warn), @logger.logged(:warn) - end - - def test_set_color_for_messages - Rails::LogSubscriber.colorize_logging = true - @log_subscriber.bar(nil) - assert_equal "\e[31mcool\e[0m, \e[1m\e[34misn't it?\e[0m", @logger.logged(:info).last - end - - def test_does_not_set_color_if_colorize_logging_is_set_to_false - @log_subscriber.bar(nil) - assert_equal "cool, isn't it?", @logger.logged(:info).last - end - - def test_event_is_sent_to_the_registered_class - Rails::LogSubscriber.add :my_log_subscriber, @log_subscriber - instrument "some_event.my_log_subscriber" - wait - assert_equal %w(some_event.my_log_subscriber), @logger.logged(:info) - end - - def test_event_is_an_active_support_notifications_event - Rails::LogSubscriber.add :my_log_subscriber, @log_subscriber - instrument "some_event.my_log_subscriber" - wait - assert_kind_of ActiveSupport::Notifications::Event, @log_subscriber.event - end - - def test_does_not_send_the_event_if_it_doesnt_match_the_class - Rails::LogSubscriber.add :my_log_subscriber, @log_subscriber - instrument "unknown_event.my_log_subscriber" - wait - # If we get here, it means that NoMethodError was not raised. - end - - def test_does_not_send_the_event_if_logger_is_nil - Rails.logger = nil - @log_subscriber.expects(:some_event).never - Rails::LogSubscriber.add :my_log_subscriber, @log_subscriber - instrument "some_event.my_log_subscriber" - wait - end - - def test_does_not_fail_with_non_namespaced_events - Rails::LogSubscriber.add :my_log_subscriber, @log_subscriber - instrument "whatever" - wait - end - - def test_flushes_loggers - Rails::LogSubscriber.add :my_log_subscriber, @log_subscriber - Rails::LogSubscriber.flush_all! - assert_equal 1, @logger.flush_count - end - - def test_flushes_the_same_logger_just_once - Rails::LogSubscriber.add :my_log_subscriber, @log_subscriber - Rails::LogSubscriber.add :another, @log_subscriber - Rails::LogSubscriber.flush_all! - wait - assert_equal 1, @logger.flush_count - end - - def test_logging_does_not_die_on_failures - Rails::LogSubscriber.add :my_log_subscriber, @log_subscriber - instrument "puke.my_log_subscriber" - instrument "some_event.my_log_subscriber" - wait - - assert_equal 1, @logger.logged(:info).size - assert_equal 'some_event.my_log_subscriber', @logger.logged(:info).last - - assert_equal 1, @logger.logged(:error).size - assert_equal 'Could not log "puke.my_log_subscriber" event. RuntimeError: puke', @logger.logged(:error).last - end -end \ No newline at end of file -- cgit v1.2.3 From b549d93d2f34a18971e691ff93e4c5b7b092eb14 Mon Sep 17 00:00:00 2001 From: Nick Sieger Date: Tue, 15 Jun 2010 15:28:19 -0500 Subject: AS::Isolation functional on Windows/JRuby. Doesn't make up for the fact that it's slooooooooow, though. Signed-off-by: wycats --- railties/test/abstract_unit.rb | 2 -- 1 file changed, 2 deletions(-) (limited to 'railties') diff --git a/railties/test/abstract_unit.rb b/railties/test/abstract_unit.rb index d04a2aa1f3..a05bae5dcc 100644 --- a/railties/test/abstract_unit.rb +++ b/railties/test/abstract_unit.rb @@ -1,5 +1,3 @@ -ORIG_ARGV = ARGV.dup - require File.expand_path("../../../load_paths", __FILE__) require 'stringio' -- cgit v1.2.3 From 974196b0910924d08640703cc558c48ca049246a Mon Sep 17 00:00:00 2001 From: Prem Sichanugrist Date: Thu, 24 Jun 2010 23:21:32 +0700 Subject: Remove obsolete test case, since we have move Rails::LogSubscriber to ActiveSupport::LogSubscriber in [6788db824ab732b13493a9d702dd8fb89fa153c8] [#4816 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- railties/test/railties/railtie_test.rb | 9 --------- 1 file changed, 9 deletions(-) (limited to 'railties') diff --git a/railties/test/railties/railtie_test.rb b/railties/test/railties/railtie_test.rb index 2accaca855..c74cc01dc1 100644 --- a/railties/test/railties/railtie_test.rb +++ b/railties/test/railties/railtie_test.rb @@ -48,15 +48,6 @@ module RailtiesTest assert_equal "hello", AppTemplate::Application.config.foo.greetings end - test "railtie can add log subscribers" do - begin - class Foo < Rails::Railtie ; log_subscriber(:foo, Rails::LogSubscriber.new) ; end - assert_kind_of Rails::LogSubscriber, Rails::LogSubscriber.log_subscribers[0] - ensure - Rails::LogSubscriber.log_subscribers.clear - end - end - test "railtie can add to_prepare callbacks" do $to_prepare = false class Foo < Rails::Railtie ; config.to_prepare { $to_prepare = true } ; end -- cgit v1.2.3 From 81c5684267b0341a1537c2db83a820bcff8dc808 Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Thu, 24 Jun 2010 12:42:09 -0400 Subject: adding middleware test for RAILS_CACHE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- railties/test/application/middleware_test.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'railties') diff --git a/railties/test/application/middleware_test.rb b/railties/test/application/middleware_test.rb index 999f666a64..e66e81ea2c 100644 --- a/railties/test/application/middleware_test.rb +++ b/railties/test/application/middleware_test.rb @@ -83,6 +83,17 @@ module ApplicationTests assert_equal "Rack::Config", middleware.second end + test "RAILS_CACHE does not respond to middleware" do + add_to_config "config.cache_store = :memory_store" + boot! + assert_equal "Rack::Runtime", middleware.third + end + + test "RAILS_CACHE does respond to middleware" do + boot! + assert_equal "Rack::Runtime", middleware.fourth + end + test "insert middleware before" do add_to_config "config.middleware.insert_before ActionDispatch::Static, Rack::Config" boot! -- cgit v1.2.3 From 67ee6c38b9b112eabe37d5869c23210b9ebf453c Mon Sep 17 00:00:00 2001 From: Prem Sichanugrist Date: Thu, 24 Jun 2010 22:05:27 +0700 Subject: Remove the --singeleton option from scaffold generator. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It turned out to be that scaffold for singeleton resource will always depend on another model, and it's not possible at the moment to make the application tests pass after generate the singeleton scafold. So, it would be better to remove it for now and probably provide another generator, such as singeleton_scaffold, in which also require the depended model name. [#4863 state:resolved] Signed-off-by: José Valim --- railties/lib/rails/generators.rb | 3 +-- .../rails/generators/erb/scaffold/scaffold_generator.rb | 7 +------ .../rails/generators/rails/resource/resource_generator.rb | 15 +-------------- .../scaffold_controller/scaffold_controller_generator.rb | 2 -- .../rails/scaffold_controller/templates/controller.rb | 2 -- .../generators/test_unit/scaffold/scaffold_generator.rb | 1 - .../test_unit/scaffold/templates/functional_test.rb | 2 -- railties/test/generators/resource_generator_test.rb | 8 -------- .../test/generators/scaffold_controller_generator_test.rb | 14 -------------- 9 files changed, 3 insertions(+), 51 deletions(-) (limited to 'railties') diff --git a/railties/lib/rails/generators.rb b/railties/lib/rails/generators.rb index 41aecea355..8794392a7d 100644 --- a/railties/lib/rails/generators.rb +++ b/railties/lib/rails/generators.rb @@ -50,7 +50,6 @@ module Rails :performance_tool => nil, :resource_controller => :controller, :scaffold_controller => :scaffold_controller, - :singleton => false, :stylesheets => true, :test_framework => nil, :template_engine => :erb @@ -334,4 +333,4 @@ module Rails paths end end -end \ No newline at end of file +end diff --git a/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb b/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb index 2db7f7bbf3..b2c8d7051b 100644 --- a/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb +++ b/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb @@ -8,17 +8,12 @@ module Erb argument :attributes, :type => :array, :default => [], :banner => "field:type field:type" - class_option :singleton, :type => :boolean, :desc => "Supply to skip index view" - def create_root_folder empty_directory File.join("app/views", controller_file_path) end def copy_view_files - views = available_views - views.delete("index") if options[:singleton] - - views.each do |view| + available_views.each do |view| filename = filename_with_extensions(view) template filename, File.join("app/views", controller_file_path, filename) end diff --git a/railties/lib/rails/generators/rails/resource/resource_generator.rb b/railties/lib/rails/generators/rails/resource/resource_generator.rb index ee302b8aad..fc070026d6 100644 --- a/railties/lib/rails/generators/rails/resource/resource_generator.rb +++ b/railties/lib/rails/generators/rails/resource/resource_generator.rb @@ -14,26 +14,13 @@ module Rails class_option :actions, :type => :array, :banner => "ACTION ACTION", :default => [], :desc => "Actions for the resource controller" - class_option :singleton, :type => :boolean, :desc => "Supply to create a singleton controller" - def add_resource_route return if options[:actions].present? route_config = class_path.collect{|namespace| "namespace :#{namespace} do " }.join(" ") - route_config << "resource#{:s unless options[:singleton]} :#{pluralize?(file_name)}" + route_config << "resources :#{file_name.pluralize}" route_config << " end" * class_path.size route route_config end - - protected - - def pluralize?(name) - if options[:singleton] - name - else - name.pluralize - end - end - end end end diff --git a/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb b/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb index 49af2974cd..2271c6f9c1 100644 --- a/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb +++ b/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb @@ -10,8 +10,6 @@ module Rails class_option :orm, :banner => "NAME", :type => :string, :required => true, :desc => "ORM to generate the controller for" - class_option :singleton, :type => :boolean, :desc => "Supply to create a singleton controller" - def create_controller_files template 'controller.rb', File.join('app/controllers', class_path, "#{controller_file_name}_controller.rb") end diff --git a/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb b/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb index 84cf58d7c4..b21340f755 100644 --- a/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb +++ b/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb @@ -1,5 +1,4 @@ class <%= controller_class_name %>Controller < ApplicationController -<% unless options[:singleton] -%> # GET <%= route_url %> # GET <%= route_url %>.xml def index @@ -10,7 +9,6 @@ class <%= controller_class_name %>Controller < ApplicationController format.xml { render :xml => @<%= plural_table_name %> } end end -<% end -%> # GET <%= route_url %>/1 # GET <%= route_url %>/1.xml diff --git a/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb b/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb index c0315c7fe6..f7e907a017 100644 --- a/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb +++ b/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb @@ -6,7 +6,6 @@ module TestUnit class ScaffoldGenerator < Base include Rails::Generators::ResourceHelpers - class_option :singleton, :type => :boolean, :desc => "Supply to create a singleton controller" check_class_collision :suffix => "ControllerTest" def create_test_files diff --git a/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb b/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb index 957ebaa522..f23e495450 100644 --- a/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb +++ b/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb @@ -5,13 +5,11 @@ class <%= controller_class_name %>ControllerTest < ActionController::TestCase @<%= singular_table_name %> = <%= table_name %>(:one) end -<% unless options[:singleton] -%> test "should get index" do get :index assert_response :success assert_not_nil assigns(:<%= table_name %>) end -<% end -%> test "should get new" do get :new diff --git a/railties/test/generators/resource_generator_test.rb b/railties/test/generators/resource_generator_test.rb index 96fd7a0a72..55d5bd6f83 100644 --- a/railties/test/generators/resource_generator_test.rb +++ b/railties/test/generators/resource_generator_test.rb @@ -59,14 +59,6 @@ class ResourceGeneratorTest < Rails::Generators::TestCase end end - def test_singleton_resource - run_generator ["account", "--singleton"] - - assert_file "config/routes.rb" do |route| - assert_match /resource :account$/, route - end - end - def test_plural_names_are_singularized content = run_generator ["accounts".freeze] assert_file "app/models/account.rb", /class Account < ActiveRecord::Base/ diff --git a/railties/test/generators/scaffold_controller_generator_test.rb b/railties/test/generators/scaffold_controller_generator_test.rb index 8040b22fe6..d55ed22975 100644 --- a/railties/test/generators/scaffold_controller_generator_test.rb +++ b/railties/test/generators/scaffold_controller_generator_test.rb @@ -78,20 +78,6 @@ class ScaffoldControllerGeneratorTest < Rails::Generators::TestCase end end - def test_generates_singleton_controller - run_generator ["User", "name:string", "age:integer", "--singleton"] - - assert_file "app/controllers/users_controller.rb" do |content| - assert_no_match /def index/, content - end - - assert_file "test/functional/users_controller_test.rb" do |content| - assert_no_match /test "should get index"/, content - end - - assert_no_file "app/views/users/index.html.erb" - end - def test_skip_helper_if_required run_generator ["User", "name:string", "age:integer", "--no-helper"] assert_no_file "app/helpers/users_helper.rb" -- cgit v1.2.3 From 0d2cebe3386e57332dc63501a17246e647cefb7a Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Thu, 24 Jun 2010 14:27:11 -0400 Subject: fixing test by replacing assert with assert_equal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- railties/test/application/initializers/frameworks_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'railties') diff --git a/railties/test/application/initializers/frameworks_test.rb b/railties/test/application/initializers/frameworks_test.rb index 604c50ec2d..7c9f67da69 100644 --- a/railties/test/application/initializers/frameworks_test.rb +++ b/railties/test/application/initializers/frameworks_test.rb @@ -40,7 +40,7 @@ module ApplicationTests RUBY require "#{app_path}/config/environment" - assert "test.rails", ActionMailer::Base.default_url_options[:host] + assert_equal "test.rails", ActionMailer::Base.default_url_options[:host] end # AS -- cgit v1.2.3 From 4e8ca7bc9a5adac45391177d5b47a33d1da93036 Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Thu, 24 Jun 2010 14:25:36 -0400 Subject: adding missing assertion and fixing the test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- railties/test/application/initializers/frameworks_test.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'railties') diff --git a/railties/test/application/initializers/frameworks_test.rb b/railties/test/application/initializers/frameworks_test.rb index 7c9f67da69..7269a7c5a8 100644 --- a/railties/test/application/initializers/frameworks_test.rb +++ b/railties/test/application/initializers/frameworks_test.rb @@ -28,8 +28,10 @@ module ApplicationTests RUBY require "#{app_path}/config/environment" - ActionController::Base.view_paths.include?(File.expand_path("app/views", app_path)) - ActionMailer::Base.view_paths.include?(File.expand_path("app/views", app_path)) + + expanded_path = File.expand_path("app/views", app_path) + assert_equal ActionController::Base.view_paths[0].to_s, expanded_path + assert_equal ActionMailer::Base.view_paths[0].to_s, expanded_path end test "allows me to configure default url options for ActionMailer" do -- cgit v1.2.3 From 6682cce0386811ffe3e6d31fc025ede0936d86c3 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Thu, 24 Jun 2010 17:38:46 -0500 Subject: Dont reload the environment, just not needed bro --- railties/lib/rails/console/app.rb | 2 -- 1 file changed, 2 deletions(-) (limited to 'railties') diff --git a/railties/lib/rails/console/app.rb b/railties/lib/rails/console/app.rb index 4a7701081b..9d9763699d 100644 --- a/railties/lib/rails/console/app.rb +++ b/railties/lib/rails/console/app.rb @@ -30,5 +30,3 @@ def reload!(print=true) ActionDispatch::Callbacks.new(Proc.new {}, false).call({}) true end - -reload!(false) -- cgit v1.2.3 From a2242a608e5c3057ec46ddffdd983d94780f90f6 Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Fri, 25 Jun 2010 10:07:09 -0400 Subject: regexp anchors can't be in route constraints --- railties/guides/source/routing.textile | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'railties') diff --git a/railties/guides/source/routing.textile b/railties/guides/source/routing.textile index 3f6bb66ee5..fe0e2f7d40 100644 --- a/railties/guides/source/routing.textile +++ b/railties/guides/source/routing.textile @@ -444,6 +444,12 @@ This route would match URLs such as +/photo/A12345+. You can more succinctly exp match 'photo/:id' => 'photos#show', :id => /[A-Z]\d{5}/ ++:constraints+ takes regular expression. However note that regexp anchors can't be used within constraints. For example following route will not work: + + +match '/:id' => 'videos#show', :constraints => {:id => /^\d/} + + h4. Request-Based Constraints You can also constrain a route based on any method on the Request object that returns a +String+. -- cgit v1.2.3 From dd5924d8ca06334898831ffede11efe2c264b5f0 Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Fri, 25 Jun 2010 14:13:47 -0400 Subject: added to_xml section for controller --- .../guides/source/action_controller_overview.textile | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'railties') diff --git a/railties/guides/source/action_controller_overview.textile b/railties/guides/source/action_controller_overview.textile index 9d8426b5de..038ca903c1 100644 --- a/railties/guides/source/action_controller_overview.textile +++ b/railties/guides/source/action_controller_overview.textile @@ -338,6 +338,25 @@ end Note that while for session values you set the key to +nil+, to delete a cookie value you should use +cookies.delete(:key)+. +h3. Rendering xml and json data + +ActionController makes it extremely easy to render +xml+ or +json+ data. If you generate a controller using scaffold then your controller would look something like this. + + +class UsersController < ApplicationController + def index + @users = User.all + respond_to do |format| + format.html # index.html.erb + format.xml { render :xml => @users} + end + end +end + + +Notice that in the above case code is render :xml => @users and not render :xml => @users.to_xml. That is because if the input is not string then rails automatically invokes +to_xml+ . + + h3. Filters Filters are methods that are run before, after or "around" a controller action. -- cgit v1.2.3 From ccc8eba4dcdee9ae07788574f7cfffe1e15c2d0a Mon Sep 17 00:00:00 2001 From: wycats Date: Fri, 25 Jun 2010 12:19:03 -0700 Subject: Change the generated Gemfile to resolve, via documentation, the issue of rspec generators being unavailable in development mode --- railties/lib/rails/generators/rails/app/templates/Gemfile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'railties') diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile index 0b922a89c0..a108968b97 100644 --- a/railties/lib/rails/generators/rails/app/templates/Gemfile +++ b/railties/lib/rails/generators/rails/app/templates/Gemfile @@ -32,8 +32,9 @@ gem '<%= gem_for_database %>'<% if require_for_database %>, :require => '<%= req # gem 'sqlite3-ruby', :require => 'sqlite3' # gem 'aws-s3', :require => 'aws/s3' -# Bundle gems for certain environments: -# gem 'rspec', :group => :test -# group :test do +# Bundle gems for the local environment. Make sure to +# put test-only gems in this group so their generators +# and rake tasks are available in development mode: +# group :development, :test do # gem 'webrat' # end -- cgit v1.2.3 From 81e9627c7f4bad6007a5f8b5b7f5d50c9b28969c Mon Sep 17 00:00:00 2001 From: Trevor Turk Date: Fri, 25 Jun 2010 18:50:56 -0500 Subject: Provide example for working around that regexp anchors can't be in route constraints --- railties/guides/source/routing.textile | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'railties') diff --git a/railties/guides/source/routing.textile b/railties/guides/source/routing.textile index fe0e2f7d40..9ff06856c3 100644 --- a/railties/guides/source/routing.textile +++ b/railties/guides/source/routing.textile @@ -447,7 +447,16 @@ match 'photo/:id' => 'photos#show', :id => /[A-Z]\d{5}/ +:constraints+ takes regular expression. However note that regexp anchors can't be used within constraints. For example following route will not work: -match '/:id' => 'videos#show', :constraints => {:id => /^\d/} +match '/:id' => 'posts#show', :constraints => {:id => /^\d/} + + +However, note that you don't need to use anchors because all routes are anchored at the start. + +For example, the following routes would allow for +posts+ with +to_param+ values like +1-hello-world+ that always begin with a number and +users+ with +to_param+ values like +david+ that never begin with a number to share the root namespace: + + +match '/:id' => 'posts#show', :constraints => { :id => /\d.+/ } +match '/:username' => 'users#show' h4. Request-Based Constraints -- cgit v1.2.3 From 8de0939708a9d4b61beafe449afb84beb24cddec Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Sun, 27 Jun 2010 23:59:01 +0200 Subject: AS guide: documents String|conversions --- .../source/active_support_core_extensions.textile | 84 ++++++++++++++++++++++ 1 file changed, 84 insertions(+) (limited to 'railties') diff --git a/railties/guides/source/active_support_core_extensions.textile b/railties/guides/source/active_support_core_extensions.textile index 0c7cdd100d..def48ffd83 100644 --- a/railties/guides/source/active_support_core_extensions.textile +++ b/railties/guides/source/active_support_core_extensions.textile @@ -1696,6 +1696,90 @@ foreign_key = options[:foreign_key] || reflection.active_record.name.foreign_key NOTE: Defined in +active_support/core_ext/string/inflections.rb+. +h4. Conversions + +h5. +constantize+ + +The method +constantize+ expects the receiver to contain the name of a constant, and tries to get you the object stored in there, assuming it is defined: + + +"ActiveRecord::Base".constantize # => ActiveRecord::Base + + +The name is assumed to be top-level, no matter whether it starts with "::" or not. No lexical context is taken into account: + + +C = 1 +module M + C = 2 + "C".constantize # => 1, same as "::C".constantize +end + + +NOTE: Defined in +active_support/core_ext/string/conversions.rb+. + +h5. +ord+ + +Ruby 1.9 defines +ord+ to be the codepoint of the first character of the receiver. Active Support backports +ord+ for single-byte encondings like ASCII or ISO-8859-1 in Ruby 1.8: + + +"a".ord # => 97 +"à".ord # => 224, in ISO-8859-1 + + +In Ruby 1.8 +ord+ doesn't work in general in UTF8 strings, use the multibyte support in Active Support for that: + + +"a".mb_chars.ord # => 97 +"à".mb_chars.ord # => 224, in UTF8 + + +Note that the 224 is different in both examples. In ISO-8859-1 "à" is represented as a single byte, 224. Its single-character representattion in UTF8 has two bytes, namely 195 and 160, but its Unicode codepoint is 224. If we call +ord+ on the UTF8 string "à" the return value will be 195 in Ruby 1.8. That is not an error, because UTF8 is unsupported, the call itself would be bogus. + +INFO: +ord+ is equivalent to +getbyte(0)+. + +NOTE: Defined in +active_support/core_ext/string/conversions.rb+. + +h5. +getbyte+ + +Active Support backports +getbyte+ from Ruby 1.9: + + +"foo".getbyte(0) # => 102, same as "foo".ord +"foo".getbyte(1) # => 111 +"foo".getbyte(9) # => nil +"foo".getbyte(-1) # => 111 + + +INFO: +getbyte+ is equivalent to +[]+. + +NOTE: Defined in +active_support/core_ext/string/conversions.rb+. + +h5. +to_date+, +to_time+, +to_datetime+ + +The methods +to_date+, +to_time+, and +to_datetime+ are basically convenience wrappers around +Date._parse+: + + +"2010-07-27".to_date # => Tue, 27 Jul 2010 +"2010-07-27 23:37:00".to_time # => Tue Jul 27 23:37:00 UTC 2010 +"2010-07-27 23:37:00".to_datetime # => Tue, 27 Jul 2010 23:37:00 +0000 + + ++to_time+ receivers an optional argument +:utc+ or +:local+, to indicate which time zone you want the time in: + + +"2010-07-27 23:42:00".to_time(:utc) # => Tue Jul 27 23:42:00 UTC 2010 +"2010-07-27 23:42:00".to_time(:local) # => Tue Jul 27 23:42:00 +0200 2010 + + +Default is +:utc+. + +Please refer to the documentation of +Date._parse+ for further details. + +INFO: The three of them return +nil+ for blank receivers. + +NOTE: Defined in +active_support/core_ext/string/conversions.rb+. + h3. Extensions to +Numeric+ h4. Bytes -- cgit v1.2.3 From c37f7d66e49ffe5ac2115cc30e5529fd1c2924a8 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Mon, 28 Jun 2010 00:04:38 +0200 Subject: your beloved and infamuous typo only spottable in github colored diff, thank you --- railties/guides/source/active_support_core_extensions.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'railties') diff --git a/railties/guides/source/active_support_core_extensions.textile b/railties/guides/source/active_support_core_extensions.textile index def48ffd83..844b9428bd 100644 --- a/railties/guides/source/active_support_core_extensions.textile +++ b/railties/guides/source/active_support_core_extensions.textile @@ -1765,7 +1765,7 @@ The methods +to_date+, +to_time+, and +to_datetime+ are basically convenience wr "2010-07-27 23:37:00".to_datetime # => Tue, 27 Jul 2010 23:37:00 +0000 -+to_time+ receivers an optional argument +:utc+ or +:local+, to indicate which time zone you want the time in: ++to_time+ receives an optional argument +:utc+ or +:local+, to indicate which time zone you want the time in: "2010-07-27 23:42:00".to_time(:utc) # => Tue Jul 27 23:42:00 UTC 2010 -- cgit v1.2.3 From 9b19a6f16cebf4257d2f0b839f6cc8ff5db5c47b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Mon, 28 Jun 2010 00:57:47 +0200 Subject: A few changes were done in this commit: * Added :autoload to engines path API and redefine usage to be in sync with 6f83a5036d8a9c3f8ed7; * Do not autoload code in *lib* for applications (now you need to explicitly require them). This makes an application behave closer to an engine (code in lib is still autoloaded for plugins); * Always autoload code in app/ for engines and plugins. This makes engines behave closer to an application and should allow us to get rid of the unloadable hack required when controllers inside engines inherit from ApplicationController; --- railties/lib/rails/application.rb | 7 +--- railties/lib/rails/application/configuration.rb | 4 +- railties/lib/rails/engine.rb | 21 +++++----- railties/lib/rails/engine/configuration.rb | 4 +- railties/lib/rails/paths.rb | 51 +++++++++++++--------- railties/lib/rails/plugin.rb | 16 ++++--- railties/test/paths_test.rb | 56 ++++++++++++------------- railties/test/railties/engine_test.rb | 4 -- railties/test/railties/plugin_test.rb | 30 +++++++++++-- railties/test/railties/shared_tests.rb | 45 ++++---------------- 10 files changed, 119 insertions(+), 119 deletions(-) (limited to 'railties') diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index aabe86715c..4a7ed2d028 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -28,7 +28,7 @@ module Rails # Besides providing the same configuration as Rails::Engine and Rails::Railtie, # the application object has several specific configurations, for example # "allow_concurrency", "cache_classes", "consider_all_requests_local", "filter_parameters", - # "logger", "reload_engines", "reload_plugins" and so forth. + # "logger", "reload_plugins" and so forth. # # Check Rails::Application::Configuration to see them all. # @@ -217,10 +217,5 @@ module Rails def initialize_generators require "rails/generators" end - - # Application is always reloadable when config.cache_classes is false. - def reloadable?(app) - true - end end end diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index e3165b2d4c..465851c0e6 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -10,7 +10,7 @@ module Rails attr_accessor :allow_concurrency, :cache_classes, :cache_store, :encoding, :consider_all_requests_local, :dependency_loading, :filter_parameters, :log_level, :logger, :middleware, - :plugins, :preload_frameworks, :reload_engines, :reload_plugins, + :plugins, :preload_frameworks, :reload_plugins, :secret_token, :serve_static_assets, :session_options, :time_zone, :whiny_nils @@ -59,7 +59,7 @@ module Rails if File.exists?("#{root}/test/mocks/#{Rails.env}") ActiveSupport::Deprecation.warn "\"Rails.root/test/mocks/#{Rails.env}\" won't be added " << "automatically to load paths anymore in future releases" - paths.mocks_path "test/mocks", :load_path => true, :glob => Rails.env + paths.mocks_path "test/mocks", :autoload => true, :glob => Rails.env end paths diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index 0a3f21fb1b..ee3e3ba040 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -142,7 +142,7 @@ module Rails # Add configured load paths to ruby load paths and remove duplicates. initializer :set_load_path, :before => :bootstrap_hook do - config.autoload_paths.reverse_each do |path| + _all_load_paths.reverse_each do |path| $LOAD_PATH.unshift(path) if File.directory?(path) end $LOAD_PATH.uniq! @@ -154,16 +154,12 @@ module Rails # This needs to be an initializer, since it needs to run once # per engine and get the engine as a block parameter initializer :set_autoload_paths, :before => :bootstrap_hook do |app| - ActiveSupport::Dependencies.autoload_paths.unshift(*config.autoload_paths) - - if reloadable?(app) - ActiveSupport::Dependencies.autoload_once_paths.unshift(*config.autoload_once_paths) - else - ActiveSupport::Dependencies.autoload_once_paths.unshift(*config.autoload_paths) - end + ActiveSupport::Dependencies.autoload_paths.unshift(*_all_autoload_paths) + ActiveSupport::Dependencies.autoload_once_paths.unshift(*config.autoload_once_paths) # Freeze so future modifications will fail rather than do nothing mysteriously config.autoload_paths.freeze + config.eager_load_paths.freeze config.autoload_once_paths.freeze end @@ -195,7 +191,6 @@ module Rails ActiveSupport.on_load(:action_controller) do prepend_view_path(views) end - ActiveSupport.on_load(:action_mailer) do prepend_view_path(views) end @@ -214,8 +209,12 @@ module Rails protected - def reloadable?(app) - app.config.reload_engines + def _all_autoload_paths + @_all_autoload_paths ||= (config.autoload_paths + config.eager_load_paths + config.autoload_once_paths).uniq + end + + def _all_load_paths + @_all_load_paths ||= (config.paths.load_paths + _all_autoload_paths).uniq end end end diff --git a/railties/lib/rails/engine/configuration.rb b/railties/lib/rails/engine/configuration.rb index 4e27180f1e..2f465670cf 100644 --- a/railties/lib/rails/engine/configuration.rb +++ b/railties/lib/rails/engine/configuration.rb @@ -42,11 +42,11 @@ module Rails end def autoload_once_paths - @autoload_once_paths ||= paths.load_once + @autoload_once_paths ||= paths.autoload_once end def autoload_paths - @autoload_paths ||= paths.load_paths + @autoload_paths ||= paths.autoload_paths end end end diff --git a/railties/lib/rails/paths.rb b/railties/lib/rails/paths.rb index 1c9e308631..7a65188a9a 100644 --- a/railties/lib/rails/paths.rb +++ b/railties/lib/rails/paths.rb @@ -25,9 +25,7 @@ module Rails def initialize(path) raise if path.is_a?(Array) - @children = {} - @path = path @root = self @all_paths = [] @@ -38,14 +36,18 @@ module Rails @all_paths end - def load_once - filter_by(:load_once?) + def autoload_once + filter_by(:autoload_once?) end def eager_load filter_by(:eager_load?) end + def autoload_paths + filter_by(:autoload?) + end + def load_paths filter_by(:load_path?) end @@ -61,15 +63,17 @@ module Rails protected def filter_by(constraint) - all_paths.map do |path| + all = [] + all_paths.each do |path| if path.send(constraint) paths = path.paths paths -= path.children.values.map { |p| p.send(constraint) ? [] : p.paths }.flatten - paths - else - [] + all.concat(paths) end - end.flatten.uniq.select { |p| File.exists?(p) } + end + all.uniq! + all.reject! { |p| !File.exists?(p) } + all end end @@ -80,15 +84,16 @@ module Rails attr_accessor :glob def initialize(root, *paths) - @options = paths.last.is_a?(::Hash) ? paths.pop : {} + options = paths.last.is_a?(::Hash) ? paths.pop : {} @children = {} @root = root @paths = paths.flatten - @glob = @options.delete(:glob) + @glob = options[:glob] - @load_once = @options[:load_once] - @eager_load = @options[:eager_load] - @load_path = @options[:load_path] || @eager_load || @load_once + autoload_once! if options[:autoload_once] + eager_load! if options[:eager_load] + autoload! if options[:autoload] + load_path! if options[:load_path] @root.all_paths << self end @@ -111,24 +116,30 @@ module Rails @paths.concat paths end - def load_once! - @load_once = true - @load_path = true + def autoload_once! + @autoload_once = true end - def load_once? - @load_once + def autoload_once? + @autoload_once end def eager_load! @eager_load = true - @load_path = true end def eager_load? @eager_load end + def autoload! + @autoload = true + end + + def autoload? + @autoload + end + def load_path! @load_path = true end diff --git a/railties/lib/rails/plugin.rb b/railties/lib/rails/plugin.rb index fcdd099135..be229cc9a2 100644 --- a/railties/lib/rails/plugin.rb +++ b/railties/lib/rails/plugin.rb @@ -61,6 +61,16 @@ module Rails @config ||= Engine::Configuration.new end + initializer :handle_lib_autoload, :before => :set_load_path do |app| + paths = if app.config.reload_plugins + config.autoload_paths + else + config.autoload_once_paths + end + + paths.concat config.paths.lib.to_a + end + initializer :load_init_rb, :before => :load_config_initializers do |app| files = %w(rails/init.rb init.rb).map { |path| File.expand_path path, root } if initrb = files.find { |path| File.file? path } @@ -77,11 +87,5 @@ module Rails raise "\"#{name}\" is a Railtie/Engine and cannot be installed as plugin" end end - - protected - - def reloadable?(app) - app.config.reload_plugins - end end end diff --git a/railties/test/paths_test.rb b/railties/test/paths_test.rb index 92c7b2ba0e..008247cb1a 100644 --- a/railties/test/paths_test.rb +++ b/railties/test/paths_test.rb @@ -120,36 +120,36 @@ class PathsTest < ActiveSupport::TestCase test "it is possible to add a path that should be loaded only once" do @root.app = "/app" - @root.app.load_once! - assert @root.app.load_once? - assert @root.load_once.include?(@root.app.paths.first) + @root.app.autoload_once! + assert @root.app.autoload_once? + assert @root.autoload_once.include?(@root.app.paths.first) end test "it is possible to add a path without assignment and specify it should be loaded only once" do - @root.app "/app", :load_once => true - assert @root.app.load_once? - assert @root.load_once.include?("/app") + @root.app "/app", :autoload_once => true + assert @root.app.autoload_once? + assert @root.autoload_once.include?("/app") end test "it is possible to add multiple paths without assignment and specify it should be loaded only once" do - @root.app "/app", "/app2", :load_once => true - assert @root.app.load_once? - assert @root.load_once.include?("/app") - assert @root.load_once.include?("/app2") + @root.app "/app", "/app2", :autoload_once => true + assert @root.app.autoload_once? + assert @root.autoload_once.include?("/app") + assert @root.autoload_once.include?("/app2") end - test "making a path load_once more than once only includes it once in @root.load_once" do + test "making a path autoload_once more than once only includes it once in @root.load_once" do @root.app = "/app" - @root.app.load_once! - @root.app.load_once! - assert_equal 1, @root.load_once.select {|p| p == @root.app.paths.first }.size + @root.app.autoload_once! + @root.app.autoload_once! + assert_equal 1, @root.autoload_once.select {|p| p == @root.app.paths.first }.size end - test "paths added to a load_once path should be added to the load_once collection" do + test "paths added to a load_once path should be added to the autoload_once collection" do @root.app = "/app" - @root.app.load_once! + @root.app.autoload_once! @root.app << "/app2" - assert_equal 2, @root.load_once.size + assert_equal 2, @root.autoload_once.size end test "it is possible to mark a path as eager" do @@ -173,11 +173,11 @@ class PathsTest < ActiveSupport::TestCase end test "it is possible to create a path without assignment and mark it both as eager and load once" do - @root.app "/app", :eager_load => true, :load_once => true + @root.app "/app", :eager_load => true, :autoload_once => true assert @root.app.eager_load? - assert @root.app.load_once? + assert @root.app.autoload_once? assert @root.eager_load.include?("/app") - assert @root.load_once.include?("/app") + assert @root.autoload_once.include?("/app") end test "making a path eager more than once only includes it once in @root.eager_paths" do @@ -218,16 +218,16 @@ class PathsTest < ActiveSupport::TestCase assert_equal ["/app"], @root.load_paths end - test "adding a path to the eager paths also adds it to the load path" do + test "a path can be marked as autoload path" do @root.app = "app" - @root.app.eager_load! - assert_equal ["/foo/bar/app"], @root.load_paths + @root.app.autoload! + @root.app.models = "app/models" + assert_equal ["/foo/bar/app"], @root.autoload_paths end - test "adding a path to the load once paths also adds it to the load path" do - @root.app = "app" - @root.app.load_once! - assert_equal ["/foo/bar/app"], @root.load_paths + test "a path can be marked as autoload on creation" do + @root.app "/app", :autoload => true + assert @root.app.autoload? + assert_equal ["/app"], @root.autoload_paths end - end diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb index 3fe01e543c..7410a10712 100644 --- a/railties/test/railties/engine_test.rb +++ b/railties/test/railties/engine_test.rb @@ -20,10 +20,6 @@ module RailtiesTest end end - def reload_config - :reload_engines - end - test "Rails::Engine itself does not respond to config" do boot_rails assert !Rails::Engine.respond_to?(:config) diff --git a/railties/test/railties/plugin_test.rb b/railties/test/railties/plugin_test.rb index 0f5f29468c..b143f56484 100644 --- a/railties/test/railties/plugin_test.rb +++ b/railties/test/railties/plugin_test.rb @@ -15,10 +15,6 @@ module RailtiesTest end end - def reload_config - :reload_plugins - end - test "Rails::Plugin itself does not respond to config" do boot_rails assert !Rails::Plugin.respond_to?(:config) @@ -37,6 +33,32 @@ module RailtiesTest assert_equal "Bukkits", Bukkits.name end + test "plugin gets added to dependency list" do + boot_rails + assert_equal "Another", Another.name + end + + test "plugin constants get reloaded if config.reload_plugins is set to true" do + add_to_config <<-RUBY + config.reload_plugins = true + RUBY + + boot_rails + + assert_equal "Another", Another.name + ActiveSupport::Dependencies.clear + @plugin.delete("lib/another.rb") + assert_raises(NameError) { Another } + end + + test "plugin constants are not reloaded by default" do + boot_rails + assert_equal "Another", Another.name + ActiveSupport::Dependencies.clear + @plugin.delete("lib/another.rb") + assert_nothing_raised { Another } + end + test "it loads the plugin's init.rb file" do boot_rails assert_equal "loaded", BUKKITS diff --git a/railties/test/railties/shared_tests.rb b/railties/test/railties/shared_tests.rb index 3f78d7d3fe..ce7c55c11c 100644 --- a/railties/test/railties/shared_tests.rb +++ b/railties/test/railties/shared_tests.rb @@ -10,51 +10,25 @@ module RailtiesTest @app ||= Rails.application end - def test_plugin_puts_its_lib_directory_on_load_path + def test_puts_its_lib_directory_on_load_path boot_rails require "another" assert_equal "Another", Another.name end - def test_plugin_paths_get_added_to_as_dependency_list - boot_rails - assert_equal "Another", Another.name - end - - def test_plugins_constants_are_not_reloaded_by_default - boot_rails - assert_equal "Another", Another.name - ActiveSupport::Dependencies.clear - @plugin.delete("lib/another.rb") - assert_nothing_raised { Another } - end - - def test_plugin_constants_get_reloaded_if_config_reload_plugins - add_to_config <<-RUBY - config.#{reload_config} = true - RUBY - - boot_rails - - assert_equal "Another", Another.name - ActiveSupport::Dependencies.clear - @plugin.delete("lib/another.rb") - assert_raises(NameError) { Another } - end - - def test_plugin_puts_its_models_directory_on_load_path + def test_puts_its_models_directory_on_autoload_path @plugin.write "app/models/my_bukkit.rb", "class MyBukkit ; end" boot_rails assert_nothing_raised { MyBukkit } end - def test_plugin_puts_its_controllers_directory_on_the_load_path + def test_puts_its_controllers_directory_on_autoload_path @plugin.write "app/controllers/bukkit_controller.rb", "class BukkitController ; end" boot_rails assert_nothing_raised { BukkitController } end - def test_plugin_adds_its_views_to_view_paths + def test_adds_its_views_to_view_paths @plugin.write "app/controllers/bukkit_controller.rb", <<-RUBY class BukkitController < ActionController::Base def index @@ -72,7 +46,7 @@ module RailtiesTest assert_equal "Hello bukkits\n", response[2].body end - def test_plugin_adds_its_views_to_view_paths_with_lower_proriority + def test_adds_its_views_to_view_paths_with_lower_proriority_than_app_ones @plugin.write "app/controllers/bukkit_controller.rb", <<-RUBY class BukkitController < ActionController::Base def index @@ -91,7 +65,7 @@ module RailtiesTest assert_equal "Hi bukkits\n", response[2].body end - def test_plugin_adds_helpers_to_controller_views + def test_adds_helpers_to_controller_views @plugin.write "app/controllers/bukkit_controller.rb", <<-RUBY class BukkitController < ActionController::Base def index @@ -116,11 +90,10 @@ module RailtiesTest assert_equal "Hello bukkits\n", response[2].body end - def test_plugin_eager_load_any_path_under_app + def test_autoload_any_path_under_app @plugin.write "app/anything/foo.rb", <<-RUBY module Foo; end RUBY - boot_rails assert Foo end @@ -269,7 +242,7 @@ YAML assert_equal "Rendered from namespace", last_response.body end - def test_plugin_initializers + def test_initializers $plugin_initializer = false @plugin.write "config/initializers/foo.rb", <<-RUBY $plugin_initializer = true @@ -279,7 +252,7 @@ YAML assert $plugin_initializer end - def test_plugin_midleware_referenced_in_configuration + def test_midleware_referenced_in_configuration @plugin.write "lib/bukkits.rb", <<-RUBY class Bukkits def initialize(app) -- cgit v1.2.3 From f61d923d284062b4e4864d81c603157020198d06 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sun, 27 Jun 2010 16:42:27 -0700 Subject: Update to latest rails.js [#4411 state:resolved] --- .../app/templates/public/javascripts/rails.js | 171 ++++++++++++++------- 1 file changed, 114 insertions(+), 57 deletions(-) (limited to 'railties') diff --git a/railties/lib/rails/generators/rails/app/templates/public/javascripts/rails.js b/railties/lib/rails/generators/rails/app/templates/public/javascripts/rails.js index c5fa02ae35..4283ed8982 100644 --- a/railties/lib/rails/generators/rails/app/templates/public/javascripts/rails.js +++ b/railties/lib/rails/generators/rails/app/templates/public/javascripts/rails.js @@ -1,87 +1,148 @@ -document.observe("dom:loaded", function() { +(function() { + // Technique from Juriy Zaytsev + // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/ + function isEventSupported(eventName) { + var el = document.createElement('div'); + eventName = 'on' + eventName; + var isSupported = (eventName in el); + if (!isSupported) { + el.setAttribute(eventName, 'return;'); + isSupported = typeof el[eventName] == 'function'; + } + el = null; + return isSupported; + } + + function isForm(element) { + return Object.isElement(element) && element.nodeName.toUpperCase() == 'FORM' + } + + function isInput(element) { + if (Object.isElement(element)) { + var name = element.nodeName.toUpperCase() + return name == 'INPUT' || name == 'SELECT' || name == 'TEXTAREA' + } + else return false + } + + var submitBubbles = isEventSupported('submit'), + changeBubbles = isEventSupported('change') + + if (!submitBubbles || !changeBubbles) { + // augment the Event.Handler class to observe custom events when needed + Event.Handler.prototype.initialize = Event.Handler.prototype.initialize.wrap( + function(init, element, eventName, selector, callback) { + init(element, eventName, selector, callback) + // is the handler being attached to an element that doesn't support this event? + if ( (!submitBubbles && this.eventName == 'submit' && !isForm(this.element)) || + (!changeBubbles && this.eventName == 'change' && !isInput(this.element)) ) { + // "submit" => "emulated:submit" + this.eventName = 'emulated:' + this.eventName + } + } + ) + } + + if (!submitBubbles) { + // discover forms on the page by observing focus events which always bubble + document.on('focusin', 'form', function(focusEvent, form) { + // special handler for the real "submit" event (one-time operation) + if (!form.retrieve('emulated:submit')) { + form.on('submit', function(submitEvent) { + var emulated = form.fire('emulated:submit', submitEvent, true) + // if custom event received preventDefault, cancel the real one too + if (emulated.returnValue === false) submitEvent.preventDefault() + }) + form.store('emulated:submit', true) + } + }) + } + + if (!changeBubbles) { + // discover form inputs on the page + document.on('focusin', 'input, select, texarea', function(focusEvent, input) { + // special handler for real "change" events + if (!input.retrieve('emulated:change')) { + input.on('change', function(changeEvent) { + input.fire('emulated:change', changeEvent, true) + }) + input.store('emulated:change', true) + } + }) + } + function handleRemote(element) { var method, url, params; + var event = element.fire("ajax:before"); + if (event.stopped) return false; + if (element.tagName.toLowerCase() === 'form') { method = element.readAttribute('method') || 'post'; url = element.readAttribute('action'); - params = element.serialize(true); + params = element.serialize(); } else { method = element.readAttribute('data-method') || 'get'; url = element.readAttribute('href'); params = {}; } - var event = element.fire("ajax:before"); - if (event.stopped) return false; - new Ajax.Request(url, { method: method, parameters: params, - asynchronous: true, evalScripts: true, - onLoading: function(request) { element.fire("ajax:loading", {request: request}); }, - onLoaded: function(request) { element.fire("ajax:loaded", {request: request}); }, - onInteractive: function(request) { element.fire("ajax:interactive", {request: request}); }, - onComplete: function(request) { element.fire("ajax:complete", {request: request}); }, - onSuccess: function(request) { element.fire("ajax:success", {request: request}); }, - onFailure: function(request) { element.fire("ajax:failure", {request: request}); } + onComplete: function(request) { element.fire("ajax:complete", request); }, + onSuccess: function(request) { element.fire("ajax:success", request); }, + onFailure: function(request) { element.fire("ajax:failure", request); } }); element.fire("ajax:after"); } function handleMethod(element) { - var method, url, token_name, token; - - method = element.readAttribute('data-method'); - url = element.readAttribute('href'); - csrf_param = $$('meta[name=csrf-param]').first(); - csrf_token = $$('meta[name=csrf-token]').first(); + var method = element.readAttribute('data-method'), + url = element.readAttribute('href'), + csrf_param = $$('meta[name=csrf-param]')[0], + csrf_token = $$('meta[name=csrf-token]')[0]; var form = new Element('form', { method: "POST", action: url, style: "display: none;" }); - element.parentNode.appendChild(form); + element.parentNode.insert(form); - if (method != 'post') { + if (method !== 'post') { var field = new Element('input', { type: 'hidden', name: '_method', value: method }); - form.appendChild(field); + form.insert(field); } if (csrf_param) { - var param = csrf_param.readAttribute('content'); - var token = csrf_token.readAttribute('content'); - var field = new Element('input', { type: 'hidden', name: param, value: token }); - form.appendChild(field); + var param = csrf_param.readAttribute('content'), + token = csrf_token.readAttribute('content'), + field = new Element('input', { type: 'hidden', name: param, value: token }); + form.insert(field); } form.submit(); } - $(document.body).observe("click", function(event) { - var message = event.findElement().readAttribute('data-confirm'); - if (message && !confirm(message)) { - event.stop(); - return false; - } - var element = event.findElement("a[data-remote]"); - if (element) { - handleRemote(element); - event.stop(); - return true; - } + document.on("click", "*[data-confirm]", function(event, element) { + var message = element.readAttribute('data-confirm'); + if (!confirm(message)) event.stop(); + }); - var element = event.findElement("a[data-method]"); - if (element) { - handleMethod(element); - event.stop(); - return true; - } + document.on("click", "a[data-remote]", function(event, element) { + if (event.stopped) return; + handleRemote(element); + event.stop(); + }); + + document.on("click", "a[data-method]", function(event, element) { + if (event.stopped) return; + handleMethod(element); + event.stop(); }); - // TODO: I don't think submit bubbles in IE - $(document.body).observe("submit", function(event) { + document.on("submit", function(event) { var element = event.findElement(), message = element.readAttribute('data-confirm'); if (message && !confirm(message)) { @@ -103,16 +164,12 @@ document.observe("dom:loaded", function() { } }); - $(document.body).observe("ajax:after", function(event) { - var element = event.findElement(); - - if (element.tagName.toLowerCase() === 'form') { - var inputs = element.select("input[type=submit][disabled=true][data-disable-with]"); - inputs.each(function(input) { - input.value = input.readAttribute('data-original-value'); - input.writeAttribute('data-original-value', null); - input.disabled = false; - }); - } + document.on("ajax:after", "form", function(event, element) { + var inputs = element.select("input[type=submit][disabled=true][data-disable-with]"); + inputs.each(function(input) { + input.value = input.readAttribute('data-original-value'); + input.removeAttribute('data-original-value'); + input.disabled = false; + }); }); -}); \ No newline at end of file +})(); -- cgit v1.2.3 From dd8b7417a9b793b7780bf5ca5e04b1c05ac3a8f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Mon, 28 Jun 2010 11:37:14 +0200 Subject: Update CHANGELOGs. --- railties/CHANGELOG | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'railties') diff --git a/railties/CHANGELOG b/railties/CHANGELOG index 61d84e104a..8e2bac7f00 100644 --- a/railties/CHANGELOG +++ b/railties/CHANGELOG @@ -1,5 +1,9 @@ *Rails 3.0.0 [Release Candidate] (unreleased)* +* Rails no longer autoload code in lib for application. You need to explicitly require it. [José Valim] + +* Rails::LogSubscriber was renamed to ActiveSupport::LogSubscriber [José Valim] + * config.load_(once_)paths in config/application.rb got renamed to config.autoload_(once_)paths. [fxn] * Abort generation/booting on Ruby 1.9.1. [fxn] -- cgit v1.2.3 From e4f9132f6a355de50511fcb75a5186a1a8af17e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Mon, 28 Jun 2010 15:36:47 +0200 Subject: Do not trigger the old mapper to avoid deprecation messages. --- railties/lib/rails/generators/rails/app/templates/config/routes.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'railties') diff --git a/railties/lib/rails/generators/rails/app/templates/config/routes.rb b/railties/lib/rails/generators/rails/app/templates/config/routes.rb index d6c0365c04..d42cf3bfdf 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/routes.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/routes.rb @@ -1,4 +1,4 @@ -<%= app_const %>.routes.draw do |map| +<%= app_const %>.routes.draw do # The priority is based upon order of creation: # first created -> highest priority. -- cgit v1.2.3 From b5b42af33f446ca3de1d80f92b8c9138dbf6c05d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Mon, 28 Jun 2010 17:09:09 +0200 Subject: Make the sentinel flag for route a bit more robust. --- railties/lib/rails/generators/actions.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'railties') diff --git a/railties/lib/rails/generators/actions.rb b/railties/lib/rails/generators/actions.rb index 7af329bbf0..199afbdc30 100644 --- a/railties/lib/rails/generators/actions.rb +++ b/railties/lib/rails/generators/actions.rb @@ -275,7 +275,7 @@ module Rails # def route(routing_code) log :route, routing_code - sentinel = "routes.draw do |map|" + sentinel = /\.routes\.draw do(\s*\|map\|)?\s*$/ in_root do inject_into_file 'config/routes.rb', "\n #{routing_code}\n", { :after => sentinel, :verbose => false } -- cgit v1.2.3 From 67582f08bf86ec71a27363554bc550e929a007f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Tue, 29 Jun 2010 19:47:04 +0200 Subject: Push a failing test for issues [#4994] and [#5003]. --- railties/test/application/loading_test.rb | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'railties') diff --git a/railties/test/application/loading_test.rb b/railties/test/application/loading_test.rb index b337d3fc6e..340ce67511 100644 --- a/railties/test/application/loading_test.rb +++ b/railties/test/application/loading_test.rb @@ -12,7 +12,7 @@ class LoadingTest < Test::Unit::TestCase @app ||= Rails.application end - def test_load_should_load_constants + def test_constants_in_app_are_autoloaded app_file "app/models/post.rb", <<-MODEL class Post < ActiveRecord::Base validates_acceptance_of :title, :accept => "omg" @@ -29,6 +29,19 @@ class LoadingTest < Test::Unit::TestCase assert_equal 'omg', p.title end + def test_models_without_table_do_not_panic_on_scope_definitions_when_loaded + app_file "app/models/user.rb", <<-MODEL + class User < ActiveRecord::Base + default_scope where(:published => true) + end + MODEL + + require "#{rails_root}/config/environment" + setup_ar! + + User + end + def test_descendants_are_cleaned_on_each_request_without_cache_classes add_to_config <<-RUBY config.cache_classes = false -- cgit v1.2.3 From d4c7d3fd94e5a885a6366eaeb3b908bb58ffd4db Mon Sep 17 00:00:00 2001 From: wycats Date: Tue, 29 Jun 2010 12:18:17 -0700 Subject: Create a deprecation behavior that triggers a notification for deprecation notices, and make the behaviors independent of the environment names. * In Rails 2.3 apps being upgraded, you will need to add the deprecation configuration to each of your environments. Failing to do so will result in the same behavior as Rails 2.3, but with an outputted warning to provide information on how to set up the setting. * New Rails 3 applications generate the setting * The notification style will send deprecation notices using ActiveSupport::Notifications. Third-party tools can listen in to these notifications to provide a streamlined view of the deprecation notices occurring in your app. * The payload in the notification is the deprecation warning itself as well as the callstack from the point that triggered the notification. --- .../rails/app/templates/config/environments/development.rb.tt | 3 +++ .../rails/app/templates/config/environments/production.rb.tt | 3 +++ .../generators/rails/app/templates/config/environments/test.rb.tt | 3 +++ railties/test/application/url_generation_test.rb | 1 + railties/test/isolation/abstract_unit.rb | 3 ++- 5 files changed, 12 insertions(+), 1 deletion(-) (limited to 'railties') diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt index f0e917dd96..99758dfcf7 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt @@ -16,4 +16,7 @@ # Don't care if the mailer can't send config.action_mailer.raise_delivery_errors = false + + # Print deprecation notices to the Rails logger + config.active_support.deprecation = :log end diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt index b9fb13b640..93407fa058 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt @@ -43,4 +43,7 @@ # Enable locale fallbacks for I18n (makes lookups for any locale fall back to # the I18n.default_locale when a translation can not be found) config.i18n.fallbacks = true + + # Send deprecation notices to registered listeners + config.active_support.deprecation = :notification end 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 beb28e2229..26cdef071a 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,4 +29,7 @@ # 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 end diff --git a/railties/test/application/url_generation_test.rb b/railties/test/application/url_generation_test.rb index 72cae23985..2b6ec26cd0 100644 --- a/railties/test/application/url_generation_test.rb +++ b/railties/test/application/url_generation_test.rb @@ -16,6 +16,7 @@ module ApplicationTests class MyApp < Rails::Application config.secret_token = "3b7cd727ee24e8444053437c36cc66c4" config.session_store :cookie_store, :key => "_myapp_session" + config.active_support.deprecation = :log end MyApp.initialize! diff --git a/railties/test/isolation/abstract_unit.rb b/railties/test/isolation/abstract_unit.rb index b46ac0efaf..390c0ab543 100644 --- a/railties/test/isolation/abstract_unit.rb +++ b/railties/test/isolation/abstract_unit.rb @@ -100,7 +100,7 @@ module TestHelpers end end - add_to_config 'config.secret_token = "3b7cd727ee24e8444053437c36cc66c4"; config.session_store :cookie_store, :key => "_myapp_session"' + add_to_config 'config.secret_token = "3b7cd727ee24e8444053437c36cc66c4"; config.session_store :cookie_store, :key => "_myapp_session"; config.active_support.deprecation = :log' end def make_basic_app @@ -110,6 +110,7 @@ module TestHelpers app = Class.new(Rails::Application) app.config.secret_token = "3b7cd727ee24e8444053437c36cc66c4" app.config.session_store :cookie_store, :key => "_myapp_session" + app.config.active_support.deprecation = :log yield app if block_given? app.initialize! -- cgit v1.2.3 From 0253bf425ea6fc112d8eecc6e7ea94e349cb538d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Tue, 29 Jun 2010 14:07:54 -0700 Subject: Change :notification to :notify (ht: m4n) --- .../generators/rails/app/templates/config/environments/production.rb.tt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'railties') diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt index 93407fa058..500fc4d860 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt @@ -45,5 +45,5 @@ config.i18n.fallbacks = true # Send deprecation notices to registered listeners - config.active_support.deprecation = :notification + config.active_support.deprecation = :notify end -- cgit v1.2.3