diff options
57 files changed, 394 insertions, 232 deletions
diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb index 1fff958ceb..d2e01cfd4c 100644 --- a/actionmailer/lib/action_mailer/base.rb +++ b/actionmailer/lib/action_mailer/base.rb @@ -398,7 +398,7 @@ module ActionMailer # Register an Observer which will be notified when mail is delivered. # Either a class or a string can be passed in as the Observer. If a string is passed in - # it will be <tt>constantize</tt>d. + # it will be +constantize+d. def register_observer(observer) delivery_observer = (observer.is_a?(String) ? observer.constantize : observer) Mail.register_observer(delivery_observer) @@ -412,12 +412,20 @@ module ActionMailer Mail.register_interceptor(delivery_interceptor) end + # Returns the name of current mailer. This method is also being used as a path for a view lookup. + # If this is an anonymous mailer, this method will return +anonymous+ instead. def mailer_name @mailer_name ||= anonymous? ? "anonymous" : name.underscore end + # Allows to set the name of current mailer. attr_writer :mailer_name alias :controller_path :mailer_name + # Sets the defaults through app configuration: + # + # config.action_mailer.default { from: "no-reply@example.org" } + # + # Aliased by ::default_options= def default(value = nil) self.default_params = default_params.merge(value).freeze if value default_params @@ -429,13 +437,15 @@ module ActionMailer # Receives a raw email, parses it into an email object, decodes it, # instantiates a new mailer, and passes the email object to the mailer - # object's +receive+ method. If you want your mailer to be able to - # process incoming messages, you'll need to implement a +receive+ - # method that accepts the raw email string as a parameter: + # object's +receive+ method. + # + # If you want your mailer to be able to process incoming messages, you'll + # need to implement a +receive+ method that accepts the raw email string + # as a parameter: # # class MyMailer < ActionMailer::Base # def receive(mail) - # ... + # # ... # end # end def receive(raw_mail) @@ -446,10 +456,12 @@ module ActionMailer end end - # Wraps an email delivery inside of Active Support Notifications instrumentation. This - # method is actually called by the <tt>Mail::Message</tt> object itself through a callback - # when you call <tt>:deliver</tt> on the Mail::Message, calling +deliver_mail+ directly - # and passing a Mail::Message will do nothing except tell the logger you sent the email. + # Wraps an email delivery inside of ActiveSupport::Notifications instrumentation. + # + # This method is actually called by the Mail::Message object itself + # through a callback when you call +:deliver+ on the Mail::Message, + # calling +deliver_mail+ directly and passing a Mail::Message will do + # nothing except tell the logger you sent the email. def deliver_mail(mail) #:nodoc: ActiveSupport::Notifications.instrument("deliver.action_mailer") do |payload| set_payload_for_mail(payload, mail) @@ -475,7 +487,7 @@ module ActionMailer payload[:mail] = mail.encoded end - def method_missing(method_name, *args) + def method_missing(method_name, *args) # :nodoc: if respond_to?(method_name) new(method_name, *args).message else @@ -512,17 +524,18 @@ module ActionMailer end end + # Returns the name of the mailer object. def mailer_name self.class.mailer_name end - # Allows you to pass random and unusual headers to the new <tt>Mail::Message</tt> object - # which will add them to itself. + # Allows you to pass random and unusual headers to the new Mail::Message + # object which will add them to itself. # # headers['X-Special-Domain-Specific-Header'] = "SecretValue" # - # You can also pass a hash into headers of header field names and values, which - # will then be set on the Mail::Message object: + # You can also pass a hash into headers of header field names and values, + # which will then be set on the Mail::Message object: # # headers 'X-Special-Domain-Specific-Header' => "SecretValue", # 'In-Reply-To' => incoming.message_id @@ -578,22 +591,22 @@ module ActionMailer # Both methods accept a headers hash. This hash allows you to specify the most used headers # in an email message, these are: # - # * <tt>:subject</tt> - The subject of the message, if this is omitted, Action Mailer will - # ask the Rails I18n class for a translated <tt>:subject</tt> in the scope of + # * +:subject+ - The subject of the message, if this is omitted, Action Mailer will + # ask the Rails I18n class for a translated +:subject+ in the scope of # <tt>[mailer_scope, action_name]</tt> or if this is missing, will translate the - # humanized version of the <tt>action_name</tt> - # * <tt>:to</tt> - Who the message is destined for, can be a string of addresses, or an array + # humanized version of the +action_name+ + # * +:to+ - Who the message is destined for, can be a string of addresses, or an array # of addresses. - # * <tt>:from</tt> - Who the message is from - # * <tt>:cc</tt> - Who you would like to Carbon-Copy on this email, can be a string of addresses, + # * +:from+ - Who the message is from + # * +:cc+ - Who you would like to Carbon-Copy on this email, can be a string of addresses, # or an array of addresses. - # * <tt>:bcc</tt> - Who you would like to Blind-Carbon-Copy on this email, can be a string of + # * +:bcc+ - Who you would like to Blind-Carbon-Copy on this email, can be a string of # addresses, or an array of addresses. - # * <tt>:reply_to</tt> - Who to set the Reply-To header of the email to. - # * <tt>:date</tt> - The date to say the email was sent on. + # * +:reply_to+ - Who to set the Reply-To header of the email to. + # * +:date+ - The date to say the email was sent on. # - # You can set default values for any of the above headers (except :date) by using the <tt>default</tt> - # class method: + # You can set default values for any of the above headers (except +:date+) + # by using the ::default class method: # # class Notifier < ActionMailer::Base # default from: 'no-reply@test.lindsaar.net', @@ -605,17 +618,19 @@ module ActionMailer # as part of the headers hash or use the <tt>headers['name'] = value</tt> # method. # - # When a <tt>:return_path</tt> is specified as header, that value will be used as the 'envelope from' - # address for the Mail message. Setting this is useful when you want delivery notifications - # sent to a different address than the one in <tt>:from</tt>. Mail will actually use the - # <tt>:return_path</tt> in preference to the <tt>:sender</tt> in preference to the <tt>:from</tt> - # field for the 'envelope from' value. + # When a +:return_path+ is specified as header, that value will be used as + # the 'envelope from' address for the Mail message. Setting this is useful + # when you want delivery notifications sent to a different address than the + # one in +:from+. Mail will actually use the +:return_path+ in preference + # to the +:sender+ in preference to the +:from+ field for the 'envelope + # from' value. # - # If you do not pass a block to the +mail+ method, it will find all templates in the - # view paths using by default the mailer name and the method name that it is being - # called from, it will then create parts for each of these templates intelligently, - # making educated guesses on correct content type and sequence, and return a fully - # prepared Mail::Message ready to call <tt>:deliver</tt> on to send. + # If you do not pass a block to the +mail+ method, it will find all + # templates in the view paths using by default the mailer name and the + # method name that it is being called from, it will then create parts for + # each of these templates intelligently, making educated guesses on correct + # content type and sequence, and return a fully prepared Mail::Message + # ready to call +:deliver+ on to send. # # For example: # @@ -650,8 +665,8 @@ module ActionMailer # format.html { render text: "<h1>Hello Mikel!</h1>" } # end # - # Which will render a <tt>multipart/alternative</tt> email with <tt>text/plain</tt> and - # <tt>text/html</tt> parts. + # Which will render a +multipart/alternative+ email with +text/plain+ and + # +text/html+ parts. # # The block syntax also allows you to customize the part headers if desired: # diff --git a/actionpack/lib/action_view/helpers/tag_helper.rb b/actionpack/lib/action_view/helpers/tag_helper.rb index 8c7524e795..3939e4737b 100644 --- a/actionpack/lib/action_view/helpers/tag_helper.rb +++ b/actionpack/lib/action_view/helpers/tag_helper.rb @@ -148,7 +148,7 @@ module ActionView attrs << tag_option(key, value, escape) end end - " #{attrs.sort * ' '}".html_safe unless attrs.empty? + " #{attrs.sort! * ' '}".html_safe unless attrs.empty? end def data_tag_option(key, value, escape) diff --git a/actionpack/test/dispatch/request/json_params_parsing_test.rb b/actionpack/test/dispatch/request/json_params_parsing_test.rb index 8d0a845f15..b62ed6a8b2 100644 --- a/actionpack/test/dispatch/request/json_params_parsing_test.rb +++ b/actionpack/test/dispatch/request/json_params_parsing_test.rb @@ -62,7 +62,7 @@ class JsonParamsParsingTest < ActionDispatch::IntegrationTest $stderr = StringIO.new # suppress the log json = "[\"person]\": {\"name\": \"David\"}}" exception = assert_raise(ActionDispatch::ParamsParser::ParseError) { post "/parse", json, {'CONTENT_TYPE' => 'application/json', 'action_dispatch.show_exceptions' => false} } - assert_equal MultiJson::DecodeError, exception.original_exception.class + assert_equal JSON::ParserError, exception.original_exception.class assert_equal exception.original_exception.message, exception.message ensure $stderr = STDERR diff --git a/activemodel/lib/active_model/lint.rb b/activemodel/lib/active_model/lint.rb index 1be2913f0b..46b446dc08 100644 --- a/activemodel/lib/active_model/lint.rb +++ b/activemodel/lib/active_model/lint.rb @@ -98,7 +98,7 @@ module ActiveModel private def model - assert @model.respond_to?(:to_model), "The object should respond_to to_model" + assert @model.respond_to?(:to_model), "The object should respond to to_model" @model.to_model end diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index a3b27425f7..772fd5999b 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,27 @@ +* Deprecate `ConnectionAdapters::SchemaStatements#distinct`, + as it is no longer used by internals. + + *Ben Woosley# + +* Fix pending migrations error when loading schema and `ActiveRecord::Base.table_name_prefix` + is not blank. + + Call `assume_migrated_upto_version` on connection to prevent it from first + being picked up in `method_missing`. + + In the base class, `Migration`, `method_missing` expects the argument to be a + table name, and calls `proper_table_name` on the arguments before sending to + `connection`. If `table_name_prefix` or `table_name_suffix` is used, the schema + version changes to `prefix_version_suffix`, breaking `rake test:prepare`. + + Fixes #10411. + + *Kyle Stevens* + +* Method `read_attribute_before_type_cast` should accept input as symbol. + + *Neeraj Singh* + * Confirm a record has not already been destroyed before decrementing counter cache. *Ben Tucker* diff --git a/activerecord/README.rdoc b/activerecord/README.rdoc index 822e460918..e04abe9b37 100644 --- a/activerecord/README.rdoc +++ b/activerecord/README.rdoc @@ -175,7 +175,7 @@ by relying on a number of conventions that make it easy for Active Record to inf complex relations and structures from a minimal amount of explicit direction. Convention over Configuration: -* No XML-files! +* No XML files! * Lots of reflection and run-time extension * Magic is not inherently a bad word diff --git a/activerecord/lib/active_record/association_relation.rb b/activerecord/lib/active_record/association_relation.rb index e2976577f6..20516bba0c 100644 --- a/activerecord/lib/active_record/association_relation.rb +++ b/activerecord/lib/active_record/association_relation.rb @@ -5,6 +5,10 @@ module ActiveRecord @association = association end + def proxy_association + @association + end + private def exec_queries diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 5e5995f566..3490057298 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -172,7 +172,7 @@ module ActiveRecord @association_cache[name] = association end - # Associations are a set of macro-like class methods for tying objects together through + # \Associations are a set of macro-like class methods for tying objects together through # foreign keys. They express relationships like "Project has one Project Manager" # or "Project belongs to a Portfolio". Each macro adds a number of methods to the # class which are specialized according to the collection or association symbol and the @@ -365,11 +365,11 @@ module ActiveRecord # there is some special behavior you should be aware of, mostly involving the saving of # associated objects. # - # You can set the :autosave option on a <tt>has_one</tt>, <tt>belongs_to</tt>, + # You can set the <tt>:autosave</tt> option on a <tt>has_one</tt>, <tt>belongs_to</tt>, # <tt>has_many</tt>, or <tt>has_and_belongs_to_many</tt> association. Setting it # to +true+ will _always_ save the members, whereas setting it to +false+ will - # _never_ save the members. More details about :autosave option is available at - # autosave_association.rb . + # _never_ save the members. More details about <tt>:autosave</tt> option is available at + # AutosaveAssociation. # # === One-to-one associations # @@ -402,7 +402,7 @@ module ActiveRecord # # == Customizing the query # - # Associations are built from <tt>Relation</tt>s, and you can use the <tt>Relation</tt> syntax + # \Associations are built from <tt>Relation</tt>s, and you can use the <tt>Relation</tt> syntax # to customize them. For example, to add a condition: # # class Blog < ActiveRecord::Base @@ -568,6 +568,8 @@ module ActiveRecord # @group.avatars << Avatar.new # this would work if User belonged_to Avatar rather than the other way around # @group.avatars.delete(@group.avatars.last) # so would this # + # == Setting Inverses + # # If you are using a +belongs_to+ on the join model, it is a good idea to set the # <tt>:inverse_of</tt> option on the +belongs_to+, which will mean that the following example # works correctly (where <tt>tags</tt> is a +has_many+ <tt>:through</tt> association): @@ -584,7 +586,26 @@ module ActiveRecord # belongs_to :tag, inverse_of: :taggings # end # - # == Nested Associations + # If you do not set the +:inverse_of+ record, the association will do its + # best to match itself up with the correct inverse. Automatic +:inverse_of+ + # detection only works on +has_many+, +has_one+, and +belongs_to+ associations. + # + # Extra options on the associations, as defined in the + # <tt>AssociationReflection::INVALID_AUTOMATIC_INVERSE_OPTIONS</tt> constant, will + # also prevent the association's inverse from being found automatically. + # + # The automatic guessing of the inverse association uses a heuristic based + # on the name of the class, so it may not work for all associations, + # especially the ones with non-standard names. + # + # You can turn off the automatic detection of inverse associations by setting + # the +:automatic_inverse_of+ option to +false+ like so: + # + # class Taggable < ActiveRecord::Base + # belongs_to :tag, automatic_inverse_of: false + # end + # + # == Nested \Associations # # You can actually specify *any* association with the <tt>:through</tt> option, including an # association which has a <tt>:through</tt> option itself. For example: @@ -627,7 +648,7 @@ module ActiveRecord # add a <tt>Commenter</tt> in the example above, there would be no way to tell how to set up the # intermediate <tt>Post</tt> and <tt>Comment</tt> objects. # - # == Polymorphic Associations + # == Polymorphic \Associations # # Polymorphic associations on models are not restricted on what types of models they # can be associated with. Rather, they specify an interface that a +has_many+ association @@ -789,7 +810,7 @@ module ActiveRecord # For example if all the addressables are either of class Person or Company then a total # of 3 queries will be executed. The list of addressable types to load is determined on # the back of the addresses loaded. This is not supported if Active Record has to fallback - # to the previous implementation of eager loading and will raise ActiveRecord::EagerLoadPolymorphicError. + # to the previous implementation of eager loading and will raise <tt>ActiveRecord::EagerLoadPolymorphicError</tt>. # The reason is that the parent model's type is a column value so its corresponding table # name cannot be put in the +FROM+/+JOIN+ clauses of that query. # @@ -1024,7 +1045,7 @@ module ActiveRecord # An empty array is returned if none are found. # [collection<<(object, ...)] # Adds one or more objects to the collection by setting their foreign keys to the collection's primary key. - # Note that this operation instantly fires update sql without waiting for the save or update call on the + # Note that this operation instantly fires update SQL without waiting for the save or update call on the # parent object, unless the parent object is a new record. # [collection.delete(object, ...)] # Removes one or more objects from the collection by setting their foreign keys to +NULL+. @@ -1060,10 +1081,10 @@ module ActiveRecord # [collection.size] # Returns the number of associated objects. # [collection.find(...)] - # Finds an associated object according to the same rules as ActiveRecord::Base.find. + # Finds an associated object according to the same rules as <tt>ActiveRecord::Base.find</tt>. # [collection.exists?(...)] # Checks whether an associated object with the given conditions exists. - # Uses the same rules as ActiveRecord::Base.exists?. + # Uses the same rules as <tt>ActiveRecord::Base.exists?</tt>. # [collection.build(attributes = {}, ...)] # Returns one or more new objects of the collection type that have been instantiated # with +attributes+ and linked to this object through a foreign key, but have not yet @@ -1082,7 +1103,7 @@ module ActiveRecord # # === Example # - # Example: A Firm class declares <tt>has_many :clients</tt>, which will add: + # A <tt>Firm</tt> class declares <tt>has_many :clients</tt>, which will add: # * <tt>Firm#clients</tt> (similar to <tt>Client.where(firm_id: id)</tt>) # * <tt>Firm#clients<<</tt> # * <tt>Firm#clients.delete</tt> @@ -1116,8 +1137,8 @@ module ActiveRecord # Controls what happens to the associated objects when # their owner is destroyed. Note that these are implemented as # callbacks, and Rails executes callbacks in order. Therefore, other - # similar callbacks may affect the :dependent behavior, and the - # :dependent behavior may affect other callbacks. + # similar callbacks may affect the <tt>:dependent</tt> behavior, and the + # <tt>:dependent</tt> behavior may affect other callbacks. # # * <tt>:destroy</tt> causes all the associated objects to also be destroyed. # * <tt>:delete_all</tt> causes all the associated objects to be deleted directly from the database (so callbacks will not be executed). @@ -1163,8 +1184,8 @@ module ActiveRecord # If true, always save the associated objects or destroy them if marked for destruction, # when saving the parent object. If false, never save or destroy the associated objects. # By default, only save associated objects that are new records. This option is implemented as a - # before_save callback. Because callbacks are run in the order they are defined, associated objects - # may need to be explicitly saved in any user-defined before_save callbacks. + # +before_save+ callback. Because callbacks are run in the order they are defined, associated objects + # may need to be explicitly saved in any user-defined +before_save+ callbacks. # # Note that <tt>accepts_nested_attributes_for</tt> sets <tt>:autosave</tt> to <tt>true</tt>. # [:inverse_of] @@ -1189,7 +1210,7 @@ module ActiveRecord # Specifies a one-to-one association with another class. This method should only be used # if the other class contains the foreign key. If the current class contains the foreign key, # then you should use +belongs_to+ instead. See also ActiveRecord::Associations::ClassMethods's overview - # on when to use has_one and when to use belongs_to. + # on when to use +has_one+ and when to use +belongs_to+. # # The following methods for retrieval and query of a single associated object will be added: # @@ -1357,7 +1378,7 @@ module ActiveRecord # class is created and decremented when it's destroyed. This requires that a column # named <tt>#{table_name}_count</tt> (such as +comments_count+ for a belonging Comment class) # is used on the associate class (such as a Post class) - that is the migration for - # <tt>#{table_name}_count</tt> is created on the associate class (such that Post.comments_count will + # <tt>#{table_name}_count</tt> is created on the associate class (such that <tt>Post.comments_count</tt> will # return the count cached, see note below). You can also specify a custom counter # cache column by providing a column name instead of a +true+/+false+ value to this # option (e.g., <tt>counter_cache: :my_custom_counter</tt>.) @@ -1439,7 +1460,7 @@ module ActiveRecord # [collection<<(object, ...)] # Adds one or more objects to the collection by creating associations in the join table # (<tt>collection.push</tt> and <tt>collection.concat</tt> are aliases to this method). - # Note that this operation instantly fires update sql without waiting for the save or update call on the + # Note that this operation instantly fires update SQL without waiting for the save or update call on the # parent object, unless the parent object is a new record. # [collection.delete(object, ...)] # Removes one or more objects from the collection by removing their associations from the join table. @@ -1462,10 +1483,10 @@ module ActiveRecord # [collection.find(id)] # Finds an associated object responding to the +id+ and that # meets the condition that it has to be associated with this object. - # Uses the same rules as ActiveRecord::Base.find. + # Uses the same rules as <tt>ActiveRecord::Base.find</tt>. # [collection.exists?(...)] # Checks whether an associated object with the given conditions exists. - # Uses the same rules as ActiveRecord::Base.exists?. + # Uses the same rules as <tt>ActiveRecord::Base.exists?</tt>. # [collection.build(attributes = {})] # Returns a new object of the collection type that has been instantiated # with +attributes+ and linked to this object through the join table, but has not yet been saved. diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index 56e57cc36e..71b64de5ea 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -847,9 +847,7 @@ module ActiveRecord # Returns a <tt>Relation</tt> object for the records in this association def scope - @association.scope.tap do |scope| - scope.proxy_association = @association - end + @association.scope end # :nodoc: diff --git a/activerecord/lib/active_record/associations/join_dependency.rb b/activerecord/lib/active_record/associations/join_dependency.rb index 28e081c03c..5b2f2d1902 100644 --- a/activerecord/lib/active_record/associations/join_dependency.rb +++ b/activerecord/lib/active_record/associations/join_dependency.rb @@ -55,6 +55,13 @@ module ActiveRecord join_parts.first end + def join_relation(relation) + join_associations.each do |association| + relation = association.join_relation(relation) + end + relation + end + def columns join_parts.collect { |join_part| table = join_part.aliased_table diff --git a/activerecord/lib/active_record/attribute_methods/before_type_cast.rb b/activerecord/lib/active_record/attribute_methods/before_type_cast.rb index a23baeaced..f596a8b02e 100644 --- a/activerecord/lib/active_record/attribute_methods/before_type_cast.rb +++ b/activerecord/lib/active_record/attribute_methods/before_type_cast.rb @@ -41,8 +41,9 @@ module ActiveRecord # task.read_attribute_before_type_cast('id') # => '1' # task.read_attribute('completed_on') # => Sun, 21 Oct 2012 # task.read_attribute_before_type_cast('completed_on') # => "2012-10-21" + # task.read_attribute_before_type_cast(:completed_on) # => "2012-10-21" def read_attribute_before_type_cast(attr_name) - @attributes[attr_name] + @attributes[attr_name.to_s] end # Returns a hash of attributes before typecasting and deserialization. diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index 566550cbe2..aabedf15e9 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -65,8 +65,7 @@ module ActiveRecord # Appends a primary key definition to the table definition. # Can be called multiple times, but this is probably not a good idea. def primary_key(name, type = :primary_key, options = {}) - options[:primary_key] = true - column(name, type, options) + column(name, type, options.merge(:primary_key => true)) end # Returns a ColumnDefinition for the column with name +name+. diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb index 9c0c4e3ef0..8ffe150de6 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -706,12 +706,21 @@ module ActiveRecord end # SELECT DISTINCT clause for a given set of columns and a given ORDER BY clause. - # Both PostgreSQL and Oracle overrides this for custom DISTINCT syntax. # - # distinct("posts.id", "posts.created_at desc") + # distinct("posts.id", ["posts.created_at desc"]) # def distinct(columns, order_by) - "DISTINCT #{columns}" + ActiveSupport::Deprecation.warn("#distinct is deprecated and shall be removed from future releases.") + "DISTINCT #{columns_for_distinct(columns, order_by)}" + end + + # Given a set of columns and an ORDER BY clause, returns the columns for a SELECT DISTINCT. + # Both PostgreSQL and Oracle overrides this for custom DISTINCT syntax - they + # require the order columns appear in the SELECT. + # + # columns_for_distinct("posts.id", ["posts.created_at desc"]) + def columns_for_distinct(columns, orders) # :nodoc: + columns end # Adds timestamps (+created_at+ and +updated_at+) columns to the named table. diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb index 98916b06a5..a651b6c32e 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb @@ -467,22 +467,17 @@ module ActiveRecord end end - # Returns a SELECT DISTINCT clause for a given set of columns and a given ORDER BY clause. - # # PostgreSQL requires the ORDER BY columns in the select list for distinct queries, and # requires that the ORDER BY include the distinct column. - # - # distinct("posts.id", ["posts.created_at desc"]) - # # => "DISTINCT posts.id, posts.created_at AS alias_0" - def distinct(columns, orders) #:nodoc: - order_columns = orders.map{ |s| + def columns_for_distinct(columns, orders) #:nodoc: + order_columns = orders.reject(&:blank?).map{ |s| # Convert Arel node to string s = s.to_sql unless s.is_a?(String) # Remove any ASC/DESC modifiers s.gsub(/\s+(ASC|DESC)\s*(NULLS\s+(FIRST|LAST)\s*)?/i, '') }.reject(&:blank?).map.with_index { |column, i| "#{column} AS alias_#{i}" } - [super].concat(order_columns).join(', ') + [super, *order_columns].join(', ') end end end diff --git a/activerecord/lib/active_record/explain_subscriber.rb b/activerecord/lib/active_record/explain_subscriber.rb index a3bc56d600..6a49936644 100644 --- a/activerecord/lib/active_record/explain_subscriber.rb +++ b/activerecord/lib/active_record/explain_subscriber.rb @@ -19,7 +19,7 @@ module ActiveRecord # On the other hand, we want to monitor the performance of our real database # queries, not the performance of the access to the query cache. IGNORED_PAYLOADS = %w(SCHEMA EXPLAIN CACHE) - EXPLAINED_SQLS = /\A\s*(select|update|delete|insert)/i + EXPLAINED_SQLS = /\A\s*(select|update|delete|insert)\b/i def ignore_payload?(payload) payload[:exception] || IGNORED_PAYLOADS.include?(payload[:name]) || payload[:sql] !~ EXPLAINED_SQLS end diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 6c020e1d57..511a1585a7 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -668,6 +668,7 @@ module ActiveRecord copied end + # Determines the version number of the next migration. def next_migration_number(number) if ActiveRecord::Base.timestamped_migrations [Time.now.utc.strftime("%Y%m%d%H%M%S"), "%.14d" % number].max diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index 0ba860a186..1f76adb367 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -8,7 +8,7 @@ module ActiveRecord self.reflections = {} end - # Reflection enables to interrogate Active Record classes and objects + # \Reflection enables to interrogate Active Record classes and objects # about their associations and aggregations. This information can, # for example, be used in a form builder that takes an Active Record object # and creates input fields for all of the attributes depending on their type @@ -100,7 +100,7 @@ module ActiveRecord # Returns the hash of options used for the macro. # # <tt>composed_of :balance, class_name: 'Money'</tt> returns <tt>{ class_name: "Money" }</tt> - # <tt>has_many :clients</tt> returns +{}+ + # <tt>has_many :clients</tt> returns <tt>{}</tt> attr_reader :options attr_reader :active_record @@ -449,8 +449,8 @@ module ActiveRecord # Checks to see if the reflection doesn't have any options that prevent # us from being able to guess the inverse automatically. First, the # +automatic_inverse_of+ option cannot be set to false. Second, we must - # have :has_many, :has_one, :belongs_to associations. Third, we must - # not have options such as :class_name or :polymorphic which prevent us + # have +has_many+, +has_one+, +belongs_to+ associations. Third, we must + # not have options such as +:polymorphic+ or +:foreign_key+ which prevent us # from correctly guessing the inverse association. # # Anything with a scope can additionally ruin our attempt at finding an @@ -493,7 +493,7 @@ module ActiveRecord delegate :foreign_key, :foreign_type, :association_foreign_key, :active_record_primary_key, :type, :to => :source_reflection - # Gets the source of the through reflection. It checks both a singularized + # Returns the source of the through reflection. It checks both a singularized # and pluralized form for <tt>:belongs_to</tt> or <tt>:has_many</tt>. # # class Post < ActiveRecord::Base @@ -507,8 +507,7 @@ module ActiveRecord # end # # tags_reflection = Post.reflect_on_association(:tags) - # - # taggings_reflection = tags_reflection.source_reflection + # tags_reflection.source_reflection # # => <ActiveRecord::Reflection::AssociationReflection: @macro=:belongs_to, @name=:tag, @active_record=Tagging, @plural_name="tags"> # def source_reflection @@ -524,7 +523,8 @@ module ActiveRecord # end # # tags_reflection = Post.reflect_on_association(:tags) - # taggings_reflection = tags_reflection.through_reflection + # tags_reflection.through_reflection + # # => <ActiveRecord::Reflection::AssociationReflection: @macro=:has_many, @name=:taggings, @active_record=Post, @plural_name="taggings"> # def through_reflection @through_reflection ||= active_record.reflect_on_association(options[:through]) diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index 913f6f88f2..ae3fa85da9 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -17,7 +17,7 @@ module ActiveRecord include FinderMethods, Calculations, SpawnMethods, QueryMethods, Batches, Explain, Delegation attr_reader :table, :klass, :loaded - attr_accessor :default_scoped, :proxy_association + attr_accessor :default_scoped alias :model :klass alias :loaded? :loaded alias :default_scoped? :default_scoped diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index 72e9272cd7..ba222aac93 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -160,7 +160,7 @@ module ActiveRecord conditions = conditions.id if Base === conditions return false if !conditions - join_dependency = construct_join_dependency_for_association_find + join_dependency = construct_join_dependency relation = construct_relation_for_association_find(join_dependency) relation = relation.except(:select, :order).select("1 AS one").limit(1) @@ -201,7 +201,7 @@ module ActiveRecord protected def find_with_associations - join_dependency = construct_join_dependency_for_association_find + join_dependency = construct_join_dependency relation = construct_relation_for_association_find(join_dependency) rows = connection.select_all(relation, 'SQL', relation.bind_values.dup) join_dependency.instantiate(rows) @@ -209,45 +209,37 @@ module ActiveRecord [] end - def construct_join_dependency_for_association_find + def construct_join_dependency(joins = []) including = (eager_load_values + includes_values).uniq - ActiveRecord::Associations::JoinDependency.new(@klass, including, []) + ActiveRecord::Associations::JoinDependency.new(@klass, including, joins) end def construct_relation_for_association_calculations - including = (eager_load_values + includes_values).uniq - join_dependency = ActiveRecord::Associations::JoinDependency.new(@klass, including, arel.froms.first) - relation = except(:includes, :eager_load, :preload) - apply_join_dependency(relation, join_dependency) + apply_join_dependency(self, construct_join_dependency(arel.froms.first)) end def construct_relation_for_association_find(join_dependency) - relation = except(:includes, :eager_load, :preload, :select).select(join_dependency.columns) + relation = except(:select).select(join_dependency.columns) apply_join_dependency(relation, join_dependency) end def apply_join_dependency(relation, join_dependency) - join_dependency.join_associations.each do |association| - relation = association.join_relation(relation) - end - - limitable_reflections = using_limitable_reflections?(join_dependency.reflections) + relation = relation.except(:includes, :eager_load, :preload) + relation = join_dependency.join_relation(relation) - if !limitable_reflections && relation.limit_value - limited_id_condition = construct_limited_ids_condition(relation.except(:select)) - relation = relation.where(limited_id_condition) + if using_limitable_reflections?(join_dependency.reflections) + relation + else + relation.where!(construct_limited_ids_condition(relation)) if relation.limit_value + relation.except(:limit, :offset) end - - relation = relation.except(:limit, :offset) unless limitable_reflections - - relation end def construct_limited_ids_condition(relation) - orders = relation.order_values.map { |val| val.presence }.compact - values = @klass.connection.distinct("#{quoted_table_name}.#{primary_key}", orders) + values = @klass.connection.columns_for_distinct( + "#{quoted_table_name}.#{quoted_primary_key}", relation.order_values) - relation = relation.dup.select(values) + relation = relation.except(:select).select(values).distinct! id_rows = @klass.connection.select_all(relation.arel, 'SQL', relation.bind_values) ids_array = id_rows.map {|row| row[primary_key]} diff --git a/activerecord/lib/active_record/relation/merger.rb b/activerecord/lib/active_record/relation/merger.rb index bda7a76330..eea43aff0e 100644 --- a/activerecord/lib/active_record/relation/merger.rb +++ b/activerecord/lib/active_record/relation/merger.rb @@ -94,9 +94,7 @@ module ActiveRecord []) relation.joins! rest - join_dependency.join_associations.each do |association| - @relation = association.join_relation(relation) - end + @relation = join_dependency.join_relation(relation) end end diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index 9fcd2d06c5..d020f1ba52 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -340,6 +340,9 @@ module ActiveRecord # User.where(name: "John", active: true).unscope(where: :name) # == User.where(active: true) # + # This method is applied before the default_scope is applied. So the conditions + # specified in default_scope will not be removed. + # # Note that this method is more generalized than ActiveRecord::SpawnMethods#except # because #except will only affect a particular relation's values. It won't wipe # the order, grouping, etc. when that relation is merged. For example: diff --git a/activerecord/lib/active_record/schema.rb b/activerecord/lib/active_record/schema.rb index 3259dbbd80..4bfd0167a4 100644 --- a/activerecord/lib/active_record/schema.rb +++ b/activerecord/lib/active_record/schema.rb @@ -43,7 +43,7 @@ module ActiveRecord unless info[:version].blank? initialize_schema_migrations_table - assume_migrated_upto_version(info[:version], migrations_paths) + connection.assume_migrated_upto_version(info[:version], migrations_paths) end end diff --git a/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb b/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb index b967bb6e0f..3968acba64 100644 --- a/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb +++ b/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb @@ -14,6 +14,10 @@ module ActiveRecord protected attr_reader :migration_action, :join_tables + # sets the default migration template that is being used for the generation of the migration + # depending on the arguments which would be sent out in the command line, the migration template + # and the table name instance variables are setup. + def set_local_assigns! @migration_template = "migration.rb" case file_name diff --git a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb index 17d77c5454..fb88ab7c09 100644 --- a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb +++ b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb @@ -226,23 +226,51 @@ module ActiveRecord end def test_distinct_zero_orders - assert_equal "DISTINCT posts.id", - @connection.distinct("posts.id", []) + assert_deprecated do + assert_equal "DISTINCT posts.id", + @connection.distinct("posts.id", []) + end + end + + def test_columns_for_distinct_zero_orders + assert_equal "posts.id", + @connection.columns_for_distinct("posts.id", []) end def test_distinct_one_order - assert_equal "DISTINCT posts.id, posts.created_at AS alias_0", - @connection.distinct("posts.id", ["posts.created_at desc"]) + assert_deprecated do + assert_equal "DISTINCT posts.id, posts.created_at AS alias_0", + @connection.distinct("posts.id", ["posts.created_at desc"]) + end + end + + def test_columns_for_distinct_one_order + assert_equal "posts.id, posts.created_at AS alias_0", + @connection.columns_for_distinct("posts.id", ["posts.created_at desc"]) end def test_distinct_few_orders - assert_equal "DISTINCT posts.id, posts.created_at AS alias_0, posts.position AS alias_1", - @connection.distinct("posts.id", ["posts.created_at desc", "posts.position asc"]) + assert_deprecated do + assert_equal "DISTINCT posts.id, posts.created_at AS alias_0, posts.position AS alias_1", + @connection.distinct("posts.id", ["posts.created_at desc", "posts.position asc"]) + end + end + + def test_columns_for_distinct_few_orders + assert_equal "posts.id, posts.created_at AS alias_0, posts.position AS alias_1", + @connection.columns_for_distinct("posts.id", ["posts.created_at desc", "posts.position asc"]) end def test_distinct_blank_not_nil_orders - assert_equal "DISTINCT posts.id, posts.created_at AS alias_0", - @connection.distinct("posts.id", ["posts.created_at desc", "", " "]) + assert_deprecated do + assert_equal "DISTINCT posts.id, posts.created_at AS alias_0", + @connection.distinct("posts.id", ["posts.created_at desc", "", " "]) + end + end + + def test_columns_for_distinct_blank_not_nil_orders + assert_equal "posts.id, posts.created_at AS alias_0", + @connection.columns_for_distinct("posts.id", ["posts.created_at desc", "", " "]) end def test_distinct_with_arel_order @@ -250,13 +278,31 @@ module ActiveRecord def order.to_sql "posts.created_at desc" end - assert_equal "DISTINCT posts.id, posts.created_at AS alias_0", - @connection.distinct("posts.id", [order]) + assert_deprecated do + assert_equal "DISTINCT posts.id, posts.created_at AS alias_0", + @connection.distinct("posts.id", [order]) + end + end + + def test_columns_for_distinct_with_arel_order + order = Object.new + def order.to_sql + "posts.created_at desc" + end + assert_equal "posts.id, posts.created_at AS alias_0", + @connection.columns_for_distinct("posts.id", [order]) end def test_distinct_with_nulls - assert_equal "DISTINCT posts.title, posts.updater_id AS alias_0", @connection.distinct("posts.title", ["posts.updater_id desc nulls first"]) - assert_equal "DISTINCT posts.title, posts.updater_id AS alias_0", @connection.distinct("posts.title", ["posts.updater_id desc nulls last"]) + assert_deprecated do + assert_equal "DISTINCT posts.title, posts.updater_id AS alias_0", @connection.distinct("posts.title", ["posts.updater_id desc nulls first"]) + assert_equal "DISTINCT posts.title, posts.updater_id AS alias_0", @connection.distinct("posts.title", ["posts.updater_id desc nulls last"]) + end + end + + def test_columns_for_distinct_with_nulls + assert_equal "posts.title, posts.updater_id AS alias_0", @connection.columns_for_distinct("posts.title", ["posts.updater_id desc nulls first"]) + assert_equal "posts.title, posts.updater_id AS alias_0", @connection.columns_for_distinct("posts.title", ["posts.updater_id desc nulls last"]) end def test_raise_error_when_cannot_translate_exception diff --git a/activerecord/test/cases/ar_schema_test.rb b/activerecord/test/cases/ar_schema_test.rb index 244e0b7179..500df52cd8 100644 --- a/activerecord/test/cases/ar_schema_test.rb +++ b/activerecord/test/cases/ar_schema_test.rb @@ -12,6 +12,8 @@ if ActiveRecord::Base.connection.supports_migrations? def teardown @connection.drop_table :fruits rescue nil + @connection.drop_table :nep_fruits rescue nil + @connection.drop_table :nep_schema_migrations rescue nil ActiveRecord::SchemaMigration.delete_all rescue nil end @@ -30,6 +32,24 @@ if ActiveRecord::Base.connection.supports_migrations? assert_equal 7, ActiveRecord::Migrator::current_version end + def test_schema_define_w_table_name_prefix + table_name = ActiveRecord::SchemaMigration.table_name + ActiveRecord::Base.table_name_prefix = "nep_" + ActiveRecord::SchemaMigration.table_name = "nep_#{table_name}" + ActiveRecord::Schema.define(:version => 7) do + create_table :fruits do |t| + t.column :color, :string + t.column :fruit_size, :string # NOTE: "size" is reserved in Oracle + t.column :texture, :string + t.column :flavor, :string + end + end + assert_equal 7, ActiveRecord::Migrator::current_version + ensure + ActiveRecord::Base.table_name_prefix = "" + ActiveRecord::SchemaMigration.table_name = table_name + end + def test_schema_raises_an_error_for_invalid_column_type assert_raise NoMethodError do ActiveRecord::Schema.define(:version => 8) do diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb index d9c032392d..a181c513ae 100644 --- a/activerecord/test/cases/attribute_methods_test.rb +++ b/activerecord/test/cases/attribute_methods_test.rb @@ -130,6 +130,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase assert_equal '10', keyboard.id_before_type_cast assert_equal nil, keyboard.read_attribute_before_type_cast('id') assert_equal '10', keyboard.read_attribute_before_type_cast('key_number') + assert_equal '10', keyboard.read_attribute_before_type_cast(:key_number) end # Syck calls respond_to? before actually calling initialize diff --git a/activerecord/test/cases/explain_subscriber_test.rb b/activerecord/test/cases/explain_subscriber_test.rb index fb53a92c89..b00e2744b9 100644 --- a/activerecord/test/cases/explain_subscriber_test.rb +++ b/activerecord/test/cases/explain_subscriber_test.rb @@ -43,6 +43,11 @@ if ActiveRecord::Base.connection.supports_explain? assert queries.empty? end + def test_collects_nothing_if_the_statement_is_only_partially_matched + SUBSCRIBER.finish(nil, nil, name: 'SQL', sql: 'select_db yo_mama') + assert queries.empty? + end + def teardown ActiveRecord::ExplainRegistry.reset end diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb index 7db9aef218..6f0de42aef 100644 --- a/activerecord/test/cases/finder_test.rb +++ b/activerecord/test/cases/finder_test.rb @@ -98,6 +98,18 @@ class FinderTest < ActiveRecord::TestCase assert !Topic.includes(:replies).limit(1).where('0 = 1').exists? end + def test_exists_with_distinct_association_includes_and_limit + author = Author.first + assert !author.unique_categorized_posts.includes(:special_comments).limit(0).exists? + assert author.unique_categorized_posts.includes(:special_comments).limit(1).exists? + end + + def test_exists_with_distinct_association_includes_limit_and_order + author = Author.first + assert !author.unique_categorized_posts.includes(:special_comments).order('comments.taggings_count DESC').limit(0).exists? + assert author.unique_categorized_posts.includes(:special_comments).order('comments.taggings_count DESC').limit(1).exists? + end + def test_exists_with_empty_table_and_no_args_given Topic.delete_all assert !Topic.exists? diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md index 2e04b17e78..493c169803 100644 --- a/activesupport/CHANGELOG.md +++ b/activesupport/CHANGELOG.md @@ -1,3 +1,16 @@ +* Replace `multi_json` with `json`. + + Since Rails requires Ruby 1.9 and since Ruby 1.9 includes `json` in the standard library, + `multi_json` is no longer necessary. + + *Erik Michaels-Ober* + +* Added escaping of U+2028 and U+2029 inside the json encoder. + These characters are legal in JSON but break the Javascript interpreter. + After escaping them, the JSON is still legal and can be parsed by Javascript. + + *Mario Caropreso + Viktor Kelemen + zackham* + * Fix skipping object callbacks using metadata fetched via callback chain inspection methods (`_*_callbacks`) diff --git a/activesupport/activesupport.gemspec b/activesupport/activesupport.gemspec index b46a331f6a..08d503ae30 100644 --- a/activesupport/activesupport.gemspec +++ b/activesupport/activesupport.gemspec @@ -21,7 +21,7 @@ Gem::Specification.new do |s| s.rdoc_options.concat ['--encoding', 'UTF-8'] s.add_dependency('i18n', '~> 0.6', '>= 0.6.4') - s.add_dependency 'multi_json', '~> 1.3' + s.add_dependency 'json', '~> 1.7' s.add_dependency 'tzinfo', '~> 0.3.37' s.add_dependency 'minitest', '~> 4.2' s.add_dependency 'thread_safe','~> 0.1' diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index 6fe7e0f4fb..a151aa03b5 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -227,7 +227,7 @@ module ActiveSupport # Compile around filters with conditions into proxy methods # that contain the conditions. # - # For `set_callback :save, :around, :filter_name, if: :condition': + # For `set_callback :save, :around, :filter_name, if: :condition`: # # def _conditional_callback_save_17 # if condition diff --git a/activesupport/lib/active_support/core_ext/string/conversions.rb b/activesupport/lib/active_support/core_ext/string/conversions.rb index d2a2db32bb..6691fc0995 100644 --- a/activesupport/lib/active_support/core_ext/string/conversions.rb +++ b/activesupport/lib/active_support/core_ext/string/conversions.rb @@ -15,6 +15,7 @@ class String # "2012-12-13 06:12".to_time # => 2012-12-13 06:12:00 +0100 # "2012-12-13T06:12".to_time # => 2012-12-13 06:12:00 +0100 # "2012-12-13T06:12".to_time(:utc) # => 2012-12-13 05:12:00 UTC + # "12/13/2012".to_time # => ArgumentError: argument out of range def to_time(form = :local) parts = Date._parse(self, false) return if parts.empty? diff --git a/activesupport/lib/active_support/core_ext/string/inflections.rb b/activesupport/lib/active_support/core_ext/string/inflections.rb index 0b506a6030..56e8a5f98d 100644 --- a/activesupport/lib/active_support/core_ext/string/inflections.rb +++ b/activesupport/lib/active_support/core_ext/string/inflections.rb @@ -185,7 +185,7 @@ class String # # Singular names are not handled correctly. # - # 'business'.classify # => "Busines" + # 'business'.classify # => "Business" def classify ActiveSupport::Inflector.classify(self) end diff --git a/activesupport/lib/active_support/json/decoding.rb b/activesupport/lib/active_support/json/decoding.rb index a4a32b2ad0..30833a4cb1 100644 --- a/activesupport/lib/active_support/json/decoding.rb +++ b/activesupport/lib/active_support/json/decoding.rb @@ -1,6 +1,6 @@ require 'active_support/core_ext/module/attribute_accessors' require 'active_support/core_ext/module/delegation' -require 'multi_json' +require 'json' module ActiveSupport # Look for and parse json strings that look like ISO 8601 times. @@ -13,8 +13,8 @@ module ActiveSupport # # ActiveSupport::JSON.decode("{\"team\":\"rails\",\"players\":\"36\"}") # => {"team" => "rails", "players" => "36"} - def decode(json, options ={}) - data = MultiJson.load(json, options) + def decode(json, proc = nil, options = {}) + data = ::JSON.load(json, proc, options) if ActiveSupport.parse_json_times convert_dates_from(data) else @@ -22,23 +22,6 @@ module ActiveSupport end end - def engine - MultiJson.adapter - end - alias :backend :engine - - def engine=(name) - MultiJson.use(name) - end - alias :backend= :engine= - - def with_backend(name) - old_backend, self.backend = backend, name - yield - ensure - self.backend = old_backend - end - # Returns the class of the error that will be raised when there is an # error in decoding JSON. Using this method means you won't directly # depend on the ActiveSupport's JSON implementation, in case it changes @@ -50,7 +33,7 @@ module ActiveSupport # Rails.logger.warn("Attempted to decode invalid JSON: #{some_string}") # end def parse_error - MultiJson::DecodeError + ::JSON::ParserError end private diff --git a/activesupport/lib/active_support/json/encoding.rb b/activesupport/lib/active_support/json/encoding.rb index 9bf1ea35b3..7f8b41d218 100644 --- a/activesupport/lib/active_support/json/encoding.rb +++ b/activesupport/lib/active_support/json/encoding.rb @@ -1,3 +1,5 @@ +#encoding: us-ascii + require 'active_support/core_ext/object/to_json' require 'active_support/core_ext/module/delegation' require 'active_support/json/variable' @@ -98,13 +100,18 @@ module ActiveSupport "\010" => '\b', "\f" => '\f', "\n" => '\n', + "\xe2\x80\xa8" => '\u2028', + "\xe2\x80\xa9" => '\u2029', "\r" => '\r', "\t" => '\t', '"' => '\"', '\\' => '\\\\', '>' => '\u003E', '<' => '\u003C', - '&' => '\u0026' } + '&' => '\u0026', + "#{0xe2.chr}#{0x80.chr}#{0xa8.chr}" => '\u2028', + "#{0xe2.chr}#{0x80.chr}#{0xa9.chr}" => '\u2029', + } class << self # If true, use ISO 8601 format for dates and times. Otherwise, fall back @@ -121,9 +128,9 @@ module ActiveSupport def escape_html_entities_in_json=(value) self.escape_regex = \ if @escape_html_entities_in_json = value - /[\x00-\x1F"\\><&]/ + /\xe2\x80\xa8|\xe2\x80\xa9|[\x00-\x1F"\\><&]/ else - /[\x00-\x1F"\\]/ + /\xe2\x80\xa8|\xe2\x80\xa9|[\x00-\x1F"\\]/ end end diff --git a/activesupport/lib/active_support/ordered_options.rb b/activesupport/lib/active_support/ordered_options.rb index c9518bda79..e03bb4ca0f 100644 --- a/activesupport/lib/active_support/ordered_options.rb +++ b/activesupport/lib/active_support/ordered_options.rb @@ -40,6 +40,14 @@ module ActiveSupport end end + # +InheritableOptions+ provides a constructor to build an +OrderedOptions+ + # hash inherited from the another hash. + # + # Use this if you already have some hash and you want to create a new one based on it. + # + # h = ActiveSupport::InheritableOptions.new({ girl: 'Mary', boy: 'John' }) + # h.girl # => 'Mary' + # h.boy # => 'John' class InheritableOptions < OrderedOptions def initialize(parent = nil) if parent.kind_of?(OrderedOptions) diff --git a/activesupport/test/json/decoding_test.rb b/activesupport/test/json/decoding_test.rb index a2d1d0dc39..34ed866848 100644 --- a/activesupport/test/json/decoding_test.rb +++ b/activesupport/test/json/decoding_test.rb @@ -55,35 +55,25 @@ class TestJSONDecoding < ActiveSupport::TestCase %q({"a":"Line1\u000aLine2"}) => {"a"=>"Line1\nLine2"} } - backends = [:ok_json] - backends << :json_gem if defined?(::JSON) - backends << :yajl if defined?(::Yajl) - - backends.each do |backend| - TESTS.each do |json, expected| - test "json decodes #{json} with the #{backend} backend" do - prev = ActiveSupport.parse_json_times - ActiveSupport.parse_json_times = true - silence_warnings do - ActiveSupport::JSON.with_backend backend do - assert_equal expected, ActiveSupport::JSON.decode(json) - end - end - ActiveSupport.parse_json_times = prev - end - end - - test "json decodes time json with time parsing disabled with the #{backend} backend" do + TESTS.each do |json, expected| + test "json decodes #{json}" do prev = ActiveSupport.parse_json_times - ActiveSupport.parse_json_times = false - expected = {"a" => "2007-01-01 01:12:34 Z"} - ActiveSupport::JSON.with_backend backend do - assert_equal expected, ActiveSupport::JSON.decode(%({"a": "2007-01-01 01:12:34 Z"})) + ActiveSupport.parse_json_times = true + silence_warnings do + assert_equal expected, ActiveSupport::JSON.decode(json) end ActiveSupport.parse_json_times = prev end end + test "json decodes time json with time parsing disabled" do + prev = ActiveSupport.parse_json_times + ActiveSupport.parse_json_times = false + expected = {"a" => "2007-01-01 01:12:34 Z"} + assert_equal expected, ActiveSupport::JSON.decode(%({"a": "2007-01-01 01:12:34 Z"})) + ActiveSupport.parse_json_times = prev + end + def test_failed_json_decoding assert_raise(ActiveSupport::JSON.parse_error) { ActiveSupport::JSON.decode(%({: 1})) } end diff --git a/activesupport/test/json/encoding_test.rb b/activesupport/test/json/encoding_test.rb index 8686dcf929..106a7fb522 100644 --- a/activesupport/test/json/encoding_test.rb +++ b/activesupport/test/json/encoding_test.rb @@ -45,8 +45,8 @@ class TestJSONEncoding < ActiveSupport::TestCase StringTests = [[ 'this is the <string>', %("this is the \\u003Cstring\\u003E")], [ 'a "string" with quotes & an ampersand', %("a \\"string\\" with quotes \\u0026 an ampersand") ], [ 'http://test.host/posts/1', %("http://test.host/posts/1")], - [ "Control characters: \x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - %("Control characters: \\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n\\u000B\\f\\r\\u000E\\u000F\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001A\\u001B\\u001C\\u001D\\u001E\\u001F") ]] + [ "Control characters: \x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\342\200\250\342\200\251", + %("Control characters: \\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n\\u000B\\f\\r\\u000E\\u000F\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001A\\u001B\\u001C\\u001D\\u001E\\u001F\\u2028\\u2029") ]] ArrayTests = [[ ['a', 'b', 'c'], %([\"a\",\"b\",\"c\"]) ], [ [1, 'a', :b, nil, false], %([1,\"a\",\"b\",null,false]) ]] diff --git a/guides/assets/images/icons/README b/guides/assets/images/icons/README index f12b2a730c..09da77fc86 100644 --- a/guides/assets/images/icons/README +++ b/guides/assets/images/icons/README @@ -1,5 +1,5 @@ Replaced the plain DocBook XSL admonition icons with Jimmac's DocBook icons (http://jimmac.musichall.cz/ikony.php3). I dropped transparency -from the Jimmac icons to get round MS IE and FOP PNG incompatibilies. +from the Jimmac icons to get round MS IE and FOP PNG incompatibilities. Stuart Rackham diff --git a/guides/source/3_0_release_notes.md b/guides/source/3_0_release_notes.md index ebe8847168..d398cd680c 100644 --- a/guides/source/3_0_release_notes.md +++ b/guides/source/3_0_release_notes.md @@ -342,7 +342,7 @@ Helpers that do something else, like `cache` or `content_for`, are not affected * Helpers now output HTML 5 by default. * Form label helper now pulls values from I18n with a single value, so `f.label :name` will pull the `:name` translation. * I18n select label on should now be :en.helpers.select instead of :en.support.select. -* You no longer need to place a minus sign at the end of a ruby interpolation inside an ERb template to remove the trailing carriage return in the HTML output. +* You no longer need to place a minus sign at the end of a Ruby interpolation inside an ERB template to remove the trailing carriage return in the HTML output. * Added `grouped_collection_select` helper to Action View. * `content_for?` has been added allowing you to check for the existence of content in a view before rendering. * passing `:value => nil` to form helpers will set the field's `value` attribute to nil as opposed to using the default value @@ -611,4 +611,3 @@ Credits See the [full list of contributors to Rails](http://contributors.rubyonrails.org/) for the many people who spent many hours making Rails 3. Kudos to all of them. Rails 3.0 Release Notes were compiled by [Mikel Lindsaar](http://lindsaar.net.) - diff --git a/guides/source/4_0_release_notes.md b/guides/source/4_0_release_notes.md index 5f2d994dd2..b9dbe820c8 100644 --- a/guides/source/4_0_release_notes.md +++ b/guides/source/4_0_release_notes.md @@ -85,7 +85,7 @@ Please refer to the [Changelog](https://github.com/rails/rails/blob/master/railt * New test locations `test/models`, `test/helpers`, `test/controllers`, and `test/mailers`. Corresponding rake tasks added as well. ([Pull Request](https://github.com/rails/rails/pull/7878)) -* Your app's executables now live in the `bin/` dir. Run `rake rails:update:bin` to get `bin/bundle`, `bin/rails`, and `bin/rake`. +* Your app's executables now live in the `bin/` directory. Run `rake rails:update:bin` to get `bin/bundle`, `bin/rails`, and `bin/rake`. * Threadsafe on by default diff --git a/guides/source/action_controller_overview.md b/guides/source/action_controller_overview.md index 43a59e8d43..28939f307f 100644 --- a/guides/source/action_controller_overview.md +++ b/guides/source/action_controller_overview.md @@ -568,10 +568,10 @@ end Note that while for session values you set the key to `nil`, to delete a cookie value you should use `cookies.delete(:key)`. -Rendering xml and json data +Rendering XML and JSON data --------------------------- -ActionController makes it extremely easy to render `xml` or `json` data. If you've generated a controller using scaffolding, it would look something like this: +ActionController makes it extremely easy to render `XML` or `JSON` data. If you've generated a controller using scaffolding, it would look something like this: ```ruby class UsersController < ApplicationController diff --git a/guides/source/active_model_basics.md b/guides/source/active_model_basics.md index 68ac26c681..1d87646e49 100644 --- a/guides/source/active_model_basics.md +++ b/guides/source/active_model_basics.md @@ -14,7 +14,7 @@ Active Model is a library containing various modules used in developing framewor ### AttributeMethods -The AttributeMethods module can add custom prefixes and suffixes on methods of a class. It is used by defining the prefixes and suffixes, which methods on the object will use them. +The AttributeMethods module can add custom prefixes and suffixes on methods of a class. It is used by defining the prefixes and suffixes and which methods on the object will use them. ```ruby class Person @@ -45,7 +45,7 @@ person.age_highest? # false ### Callbacks -Callbacks gives Active Record style callbacks. This provides the ability to define the callbacks and those will run at appropriate time. After defining a callbacks you can wrap with before, after and around custom methods. +Callbacks gives Active Record style callbacks. This provides an ability to define callbacks which run at appropriate times. After defining callbacks, you can wrap them with before, after and around custom methods. ```ruby class Person @@ -57,19 +57,19 @@ class Person def update run_callbacks(:update) do - # This will call when we are trying to call update on object. + # This method is called when update is called on an object. end end def reset_me - # This method will call when you are calling update on object as a before_update callback as defined. + # This method is called when update is called on an object as a before_update callback is defined. end end ``` ### Conversion -If a class defines `persisted?` and `id` methods then you can include `Conversion` module in that class and you can able to call Rails conversion methods to objects of that class. +If a class defines `persisted?` and `id` methods, then you can include the `Conversion` module in that class and call the Rails conversion methods on objects of that class. ```ruby class Person diff --git a/guides/source/active_record_querying.md b/guides/source/active_record_querying.md index 80eec428c1..19b214f114 100644 --- a/guides/source/active_record_querying.md +++ b/guides/source/active_record_querying.md @@ -732,7 +732,7 @@ The `reorder` method overrides the default scope order. For example: class Post < ActiveRecord::Base .. .. - has_many :comments, order: 'posted_at DESC' + has_many :comments, -> { order('posted_at DESC') } end Post.find(10).comments.reorder('name') diff --git a/guides/source/active_support_core_extensions.md b/guides/source/active_support_core_extensions.md index 6daad33dea..c012ded888 100644 --- a/guides/source/active_support_core_extensions.md +++ b/guides/source/active_support_core_extensions.md @@ -166,7 +166,7 @@ NOTE: Defined in `active_support/core_ext/object/duplicable.rb`. ### `deep_dup` -The `deep_dup` method returns deep copy of a given object. Normally, when you `dup` an object that contains other objects, ruby does not `dup` them, so it creates a shallow copy of the object. If you have an array with a string, for example, it will look like this: +The `deep_dup` method returns deep copy of a given object. Normally, when you `dup` an object that contains other objects, Ruby does not `dup` them, so it creates a shallow copy of the object. If you have an array with a string, for example, it will look like this: ```ruby array = ['string'] diff --git a/guides/source/asset_pipeline.md b/guides/source/asset_pipeline.md index a2849dd98f..b86c7bfc4e 100644 --- a/guides/source/asset_pipeline.md +++ b/guides/source/asset_pipeline.md @@ -430,7 +430,7 @@ in scope in development mode regardless of the value of this flag. Changing this engines. Engines can define assets for precompilation as well. Since the complete environment is not loaded, engines (or other gems) will not be loaded, which can cause missing assets. -Capistrano (v2.8.0 and above) includes a recipe to handle this in deployment. Add the following line to `Capfile`: +Capistrano (v2.15.1 and above) includes a recipe to handle this in deployment. Add the following line to `Capfile`: ```ruby load 'deploy/assets' diff --git a/guides/source/association_basics.md b/guides/source/association_basics.md index 8d203d265a..16a5241319 100644 --- a/guides/source/association_basics.md +++ b/guides/source/association_basics.md @@ -693,6 +693,17 @@ There are a few limitations to `inverse_of` support: * They do not work with `:as` associations. * For `belongs_to` associations, `has_many` inverse associations are ignored. +Every association will attempt to automatically find the inverse association +and set the `:inverse_of` option heuristically (based on the association name). +Most associations with standard names will be supported. However, associations +that contain the following options will not have their inverses set +automatically: + +* :conditions +* :through +* :polymorphic +* :foreign_key + Detailed Association Reference ------------------------------ diff --git a/guides/source/credits.html.erb b/guides/source/credits.html.erb index 74ae7216e1..10dd8178fb 100644 --- a/guides/source/credits.html.erb +++ b/guides/source/credits.html.erb @@ -40,7 +40,7 @@ Oscar Del Ben is a software engineer at <a href="http://www.wildfireapp.com/">Wi <% end %> <%= author('Tore Darell', 'toretore') do %> - Tore Darell is an independent developer based in Menton, France who specialises in cruft-free web applications using Ruby, Rails and unobtrusive JavaScript. His home on the internet is his blog <a href="http://tore.darell.no">Sneaky Abstractions</a>. + Tore Darell is an independent developer based in Menton, France who specialises in cruft-free web applications using Ruby, Rails and unobtrusive JavaScript. His home on the Internet is his blog <a href="http://tore.darell.no">Sneaky Abstractions</a>. <% end %> <%= author('Jeff Dean', 'zilkey') do %> diff --git a/guides/source/development_dependencies_install.md b/guides/source/development_dependencies_install.md index ef622103f4..5647a4c1b7 100644 --- a/guides/source/development_dependencies_install.md +++ b/guides/source/development_dependencies_install.md @@ -5,6 +5,10 @@ This guide covers how to setup an environment for Ruby on Rails core development After reading this guide, you will know: +* How to set up your machine for Rails development +* How to run specific groups of unit tests from the Rails test suite +* How the ActiveRecord portion of the Rails test suite operates + -------------------------------------------------------------------------------- The Easy Way @@ -53,7 +57,7 @@ If you are on Fedora or CentOS, you can run $ sudo yum install libxml2 libxml2-devel libxslt libxslt-devel ``` -If you have any problems with these libraries, you should install them manually compiling the source code. Just follow the instructions at the [Red Hat/CentOS section of the Nokogiri tutorials](http://nokogiri.org/tutorials/installing_nokogiri.html#red_hat__centos) . +If you have any problems with these libraries, you can install them manually by compiling the source code. Just follow the instructions at the [Red Hat/CentOS section of the Nokogiri tutorials](http://nokogiri.org/tutorials/installing_nokogiri.html#red_hat__centos) . Also, SQLite3 and its development files for the `sqlite3-ruby` gem — in Ubuntu you're done with just @@ -93,7 +97,7 @@ $ cd actionpack $ bundle exec rake test ``` -If you want to run the tests located in a specific directory use the `TEST_DIR` environment variable. For example, this will run the tests of the `railties/test/generators` directory only: +If you want to run the tests located in a specific directory use the `TEST_DIR` environment variable. For example, this will run the tests in the `railties/test/generators` directory only: ```bash $ cd railties @@ -133,14 +137,14 @@ $ sudo yum install mysql-server mysql-devel $ sudo yum install postgresql-server postgresql-devel ``` -After that run: +After that, run: ```bash $ rm .bundle/config $ bundle install ``` -We need first to delete `.bundle/config` because Bundler remembers in that file that we didn't want to install the "db" group (alternatively you can edit the file). +First, we need to delete `.bundle/config` because Bundler remembers in that file that we didn't want to install the "db" group (alternatively you can edit the file). In order to be able to run the test suite against MySQL you need to create a user named `rails` with privileges on the test databases: diff --git a/guides/source/getting_started.md b/guides/source/getting_started.md index 46115afb8c..599e47949d 100644 --- a/guides/source/getting_started.md +++ b/guides/source/getting_started.md @@ -29,7 +29,7 @@ prerequisites installed: Rails is a web application framework running on the Ruby programming language. If you have no prior experience with Ruby, you will find a very steep learning curve diving straight into Rails. There are some good free resources on the -internet for learning Ruby, including: +Internet for learning Ruby, including: * [Mr. Neighborly's Humble Little Ruby Book](http://www.humblelittlerubybook.com) * [Programming Ruby](http://www.ruby-doc.org/docs/ProgrammingRuby/) @@ -853,8 +853,7 @@ it look as follows: ```html+erb <h1>Editing post</h1> -<%= form_for :post, url: post_path(@post.id) }, -method: :patch do |f| %> +<%= form_for :post, url: post_path(@post.id), method: :patch do |f| %> <% if @post.errors.any? %> <div id="errorExplanation"> <h2><%= pluralize(@post.errors.count, "error") %> prohibited @@ -934,7 +933,7 @@ appear next to the "Show" link: <tr> <td><%= post.title %></td> <td><%= post.text %></td> - <td><%= link_to 'Show', post_path %></td> + <td><%= link_to 'Show', post_path(post) %></td> <td><%= link_to 'Edit', edit_post_path(post) %></td> </tr> <% end %> @@ -1076,7 +1075,7 @@ together. <tr> <td><%= post.title %></td> <td><%= post.text %></td> - <td><%= link_to 'Show', post_path %></td> + <td><%= link_to 'Show', post_path(post) %></td> <td><%= link_to 'Edit', edit_post_path(post) %></td> <td><%= link_to 'Destroy', post_path(post), method: :delete, data: { confirm: 'Are you sure?' } %></td> @@ -1149,19 +1148,17 @@ class CreateComments < ActiveRecord::Migration create_table :comments do |t| t.string :commenter t.text :body - t.references :post + t.references :post, index: true t.timestamps end - - add_index :comments, :post_id end end ``` The `t.references` line sets up a foreign key column for the association between -the two models. And the `add_index` line sets up an index for this association -column. Go ahead and run the migration: +the two models. An index for this association is also created on this column. +Go ahead and run the migration: ```bash $ rake db:migrate @@ -1173,10 +1170,8 @@ run against the current database, so in this case you will just see: ```bash == CreateComments: migrating ================================================= -- create_table(:comments) - -> 0.0008s --- add_index(:comments, :post_id) - -> 0.0003s -== CreateComments: migrated (0.0012s) ======================================== + -> 0.0115s +== CreateComments: migrated (0.0119s) ======================================== ``` ### Associating Models diff --git a/guides/source/initialization.md b/guides/source/initialization.md index 72d56b7feb..9fcd530183 100644 --- a/guides/source/initialization.md +++ b/guides/source/initialization.md @@ -114,7 +114,7 @@ If we used `s` rather than `server`, Rails will use the `aliases` defined in the ```ruby when 'server' - # Change to the application's path if there is no config.ru file in current dir. + # Change to the application's path if there is no config.ru file in current directory. # This allows us to run `rails server` from other directories, but still get # the main config.ru and properly set the tmp directory. Dir.chdir(File.expand_path('../../', APP_PATH)) unless File.exists?(File.expand_path("config.ru")) diff --git a/guides/source/migrations.md b/guides/source/migrations.md index 9c92efd521..fcfc54a3d7 100644 --- a/guides/source/migrations.md +++ b/guides/source/migrations.md @@ -852,7 +852,7 @@ end # app/models/product.rb class Product < ActiveRecord::Base - validates :flag, presence: true + validates :flag, :inclusion => { :in => [true, false] } end ``` @@ -877,7 +877,8 @@ end # app/models/product.rb class Product < ActiveRecord::Base - validates :flag, :fuzz, presence: true + validates :flag, :inclusion => { :in => [true, false] } + validates :fuzz, presence: true end ``` diff --git a/guides/source/routing.md b/guides/source/routing.md index f4cb8fe15b..c26a827172 100644 --- a/guides/source/routing.md +++ b/guides/source/routing.md @@ -857,7 +857,7 @@ resources :user_permissions, controller: 'admin/user_permissions' This will route to the `Admin::UserPermissions` controller. NOTE: Only the directory notation is supported. Specifying the -controller with ruby constant notation (eg. `:controller => +controller with Ruby constant notation (eg. `:controller => 'Admin::UserPermissions'`) can lead to routing problems and results in a warning. diff --git a/guides/source/security.md b/guides/source/security.md index b2d09369e2..f04129acdb 100644 --- a/guides/source/security.md +++ b/guides/source/security.md @@ -58,7 +58,7 @@ WARNING: _Stealing a user's session id lets an attacker use the web application Many web applications have an authentication system: a user provides a user name and password, the web application checks them and stores the corresponding user id in the session hash. From now on, the session is valid. On every request the application will load the user, identified by the user id in the session, without the need for new authentication. The session id in the cookie identifies the session. -Hence, the cookie serves as temporary authentication for the web application. Everyone who seizes a cookie from someone else, may use the web application as this user – with possibly severe consequences. Here are some ways to hijack a session, and their countermeasures: +Hence, the cookie serves as temporary authentication for the web application. Anyone who seizes a cookie from someone else, may use the web application as this user – with possibly severe consequences. Here are some ways to hijack a session, and their countermeasures: * Sniff the cookie in an insecure network. A wireless LAN can be an example of such a network. In an unencrypted wireless LAN it is especially easy to listen to the traffic of all connected clients. This is one more reason not to work from a coffee shop. For the web application builder this means to _provide a secure connection over SSL_. In Rails 3.1 and later, this could be accomplished by always forcing SSL connection in your application config file: @@ -268,7 +268,7 @@ def legacy end ``` -This will redirect the user to the main action if he tried to access a legacy action. The intention was to preserve the URL parameters to the legacy action and pass them to the main action. However, it can exploited by an attacker if he includes a host key in the URL: +This will redirect the user to the main action if he tried to access a legacy action. The intention was to preserve the URL parameters to the legacy action and pass them to the main action. However, it can be exploited by an attacker if he includes a host key in the URL: ``` http://www.example.com/site/legacy?param1=xy¶m2=23&host=www.attacker.com @@ -942,7 +942,7 @@ Or you can remove them. config.action_dispatch.default_headers.clear ``` -Here is the list of common headers: +Here is a list of common headers: * X-Frame-Options _'SAMEORIGIN' in Rails by default_ - allow framing on same domain. Set it to 'DENY' to deny framing at all or 'ALLOWALL' if you want to allow framing for all website. diff --git a/guides/source/upgrading_ruby_on_rails.md b/guides/source/upgrading_ruby_on_rails.md index 51d6775c3e..1d14656f79 100644 --- a/guides/source/upgrading_ruby_on_rails.md +++ b/guides/source/upgrading_ruby_on_rails.md @@ -118,7 +118,7 @@ Please read [Pull Request #9978](https://github.com/rails/rails/pull/9978) for d * Rails 4.0 changes the default memcached client from `memcache-client` to `dalli`. To upgrade, simply add `gem 'dalli'` to your `Gemfile`. -* Rails 4.0 deprecates the `dom_id` and `dom_class` methods. You will need to include the `ActionView::RecordIdentifier` module in controllers requiring this feature. +* Rails 4.0 deprecates the `dom_id` and `dom_class` methods in controllers (they are fine in views). You will need to include the `ActionView::RecordIdentifier` module in controllers requiring this feature. * Rails 4.0 changed how `assert_generates`, `assert_recognizes`, and `assert_routing` work. Now all these assertions raise `Assertion` instead of `ActionController::RoutingError`. diff --git a/railties/lib/rails/generators/rails/model/USAGE b/railties/lib/rails/generators/rails/model/USAGE index 1998a392aa..145d9ee6e0 100644 --- a/railties/lib/rails/generators/rails/model/USAGE +++ b/railties/lib/rails/generators/rails/model/USAGE @@ -46,18 +46,18 @@ Available field types: `rails generate model photo title:string album:references` - It will generate an album_id column. You should generate this kind of fields when - you will use a `belongs_to` association for instance. `references` also support - the polymorphism, you could enable the polymorphism like this: + It will generate an `album_id` column. You should generate these kinds of fields when + you will use a `belongs_to` association, for instance. `references` also supports + polymorphism, you can enable polymorphism like this: `rails generate model product supplier:references{polymorphic}` - For integer, string, text and binary fields an integer in curly braces will + For integer, string, text and binary fields, an integer in curly braces will be set as the limit: `rails generate model user pseudo:string{30}` - For decimal two integers separated by a comma in curly braces will be used + For decimal, two integers separated by a comma in curly braces will be used for precision and scale: `rails generate model product price:decimal{10,2}` diff --git a/railties/lib/rails/tasks/documentation.rake b/railties/lib/rails/tasks/documentation.rake index d45e892424..8544890553 100644 --- a/railties/lib/rails/tasks/documentation.rake +++ b/railties/lib/rails/tasks/documentation.rake @@ -44,11 +44,6 @@ else end namespace :doc do - def gem_path(gem_name) - path = $LOAD_PATH.grep(/#{gem_name}[\w.-]*\/lib$/).first - yield File.dirname(path) if path - end - RDocTaskWithoutDescriptions.new("app") { |rdoc| rdoc.rdoc_dir = 'doc/app' rdoc.template = ENV['template'] if ENV['template'] |