diff options
| -rw-r--r-- | actionview/CHANGELOG.md | 6 | ||||
| -rw-r--r-- | actionview/lib/action_view/helpers/tags/collection_check_boxes.rb | 17 | ||||
| -rw-r--r-- | actionview/test/template/form_collections_helper_test.rb | 7 | ||||
| -rw-r--r-- | actionview/test/template/form_helper_test.rb | 2 | ||||
| -rw-r--r-- | activerecord/lib/active_record/associations/has_many_association.rb | 2 | ||||
| -rw-r--r-- | activerecord/lib/active_record/associations/has_many_through_association.rb | 2 | ||||
| -rw-r--r-- | activerecord/lib/active_record/attribute_methods/serialization.rb | 21 | ||||
| -rw-r--r-- | activerecord/test/cases/associations/belongs_to_associations_test.rb | 6 | ||||
| -rw-r--r-- | activerecord/test/cases/attribute_methods_test.rb | 8 | ||||
| -rw-r--r-- | guides/source/3_0_release_notes.md | 2 | ||||
| -rw-r--r-- | guides/source/3_2_release_notes.md | 2 | ||||
| -rw-r--r-- | guides/source/asset_pipeline.md | 8 | ||||
| -rw-r--r-- | guides/source/association_basics.md | 2 | ||||
| -rw-r--r-- | guides/source/getting_started.md | 6 | ||||
| -rw-r--r-- | guides/source/security.md | 4 | 
15 files changed, 68 insertions, 27 deletions
diff --git a/actionview/CHANGELOG.md b/actionview/CHANGELOG.md index 8c6db33be7..0302077e1c 100644 --- a/actionview/CHANGELOG.md +++ b/actionview/CHANGELOG.md @@ -1,3 +1,9 @@ +*   `collection_check_boxes` respects `:index` option for the hidden filed name. + +    Fixes #14147. + +    *Vasiliy Ermolovich* +  *   `date_select` helper with option `with_css_classes: true` does not overwrite other classes.      *Izumi Wong-Horiuchi* diff --git a/actionview/lib/action_view/helpers/tags/collection_check_boxes.rb b/actionview/lib/action_view/helpers/tags/collection_check_boxes.rb index 8b28e4fc33..6242a2a085 100644 --- a/actionview/lib/action_view/helpers/tags/collection_check_boxes.rb +++ b/actionview/lib/action_view/helpers/tags/collection_check_boxes.rb @@ -28,10 +28,7 @@ module ActionView            # Append a hidden field to make sure something will be sent back to the            # server if all check boxes are unchecked.            if @options.fetch(:include_hidden, true) -            hidden_name = @html_options[:name] || "#{tag_name}[]" -            hidden = @template_object.hidden_field_tag(hidden_name, "", :id => nil) - -            rendered_collection + hidden +            rendered_collection + hidden_field            else              rendered_collection            end @@ -42,6 +39,18 @@ module ActionView          def render_component(builder)            builder.check_box + builder.label          end + +        def hidden_field +          hidden_name = @html_options[:name] + +          hidden_name ||= if @options.has_key?(:index) +            "#{tag_name_with_index(@options[:index])}[]" +          else +            "#{tag_name}[]" +          end + +          @template_object.hidden_field_tag(hidden_name, "", id: nil) +        end        end      end    end diff --git a/actionview/test/template/form_collections_helper_test.rb b/actionview/test/template/form_collections_helper_test.rb index 8107529149..5e991d87ad 100644 --- a/actionview/test/template/form_collections_helper_test.rb +++ b/actionview/test/template/form_collections_helper_test.rb @@ -221,6 +221,13 @@ class FormCollectionsHelperTest < ActionView::TestCase      assert_select "input[type=hidden][name='user[other_category_ids][]'][value=]", :count => 1    end +  test 'collection check boxes generates a hidden field with index if it was provided' do +    collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')] +    with_collection_check_boxes :user, :category_ids, collection, :id, :name, { index: 322 } + +    assert_select "input[type=hidden][name='user[322][category_ids][]'][value=]", count: 1 +  end +    test 'collection check boxes does not generate a hidden field if include_hidden option is false' do      collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')]      with_collection_check_boxes :user, :category_ids, collection, :id, :name, include_hidden: false diff --git a/actionview/test/template/form_helper_test.rb b/actionview/test/template/form_helper_test.rb index b5e9801776..155801dd02 100644 --- a/actionview/test/template/form_helper_test.rb +++ b/actionview/test/template/form_helper_test.rb @@ -1420,7 +1420,7 @@ class FormHelperTest < ActionView::TestCase      expected = whole_form("/posts", "new_post", "new_post") do        "<input checked='checked' id='post_1_tag_ids_1' name='post[1][tag_ids][]' type='checkbox' value='1' />" +        "<label for='post_1_tag_ids_1'>Tag 1</label>" + -      "<input name='post[tag_ids][]' type='hidden' value='' />" +      "<input name='post[1][tag_ids][]' type='hidden' value='' />"      end      assert_dom_equal expected, output_buffer diff --git a/activerecord/lib/active_record/associations/has_many_association.rb b/activerecord/lib/active_record/associations/has_many_association.rb index 3e4b7902c0..aac85a36c8 100644 --- a/activerecord/lib/active_record/associations/has_many_association.rb +++ b/activerecord/lib/active_record/associations/has_many_association.rb @@ -58,7 +58,7 @@ module ActiveRecord          # the loaded flag is set to true as well.          def count_records            count = if has_cached_counter? -            owner.send(:read_attribute, cached_counter_attribute_name) +            owner.read_attribute cached_counter_attribute_name            else              scope.count            end diff --git a/activerecord/lib/active_record/associations/has_many_through_association.rb b/activerecord/lib/active_record/associations/has_many_through_association.rb index c2eff0d8ce..73baefb8e1 100644 --- a/activerecord/lib/active_record/associations/has_many_through_association.rb +++ b/activerecord/lib/active_record/associations/has_many_through_association.rb @@ -18,7 +18,7 @@ module ActiveRecord        # SELECT query if you use #length.        def size          if has_cached_counter? -          owner.send(:read_attribute, cached_counter_attribute_name) +          owner.read_attribute cached_counter_attribute_name(reflection)          elsif loaded?            target.size          else diff --git a/activerecord/lib/active_record/attribute_methods/serialization.rb b/activerecord/lib/active_record/attribute_methods/serialization.rb index 67abbbc2a0..c3466153d6 100644 --- a/activerecord/lib/active_record/attribute_methods/serialization.rb +++ b/activerecord/lib/active_record/attribute_methods/serialization.rb @@ -30,7 +30,8 @@ module ActiveRecord          # ==== Parameters          #          # * +attr_name+ - The field name that should be serialized. -        # * +class_name+ - Optional, class name that the object type should be equal to. +        # * +class_name_or_coder+ - Optional, a coder object, which responds to `.load` / `.dump` +        #   or a class name that the object type should be equal to.          #          # ==== Example          # @@ -38,13 +39,23 @@ module ActiveRecord          #   class User < ActiveRecord::Base          #     serialize :preferences          #   end -        def serialize(attr_name, class_name = Object) +        # +        #   # Serialize preferences using JSON as coder. +        #   class User < ActiveRecord::Base +        #     serialize :preferences, JSON +        #   end +        # +        #   # Serialize preferences as Hash using YAML coder. +        #   class User < ActiveRecord::Base +        #     serialize :preferences, Hash +        #   end +        def serialize(attr_name, class_name_or_coder = Object)            include Behavior -          coder = if [:load, :dump].all? { |x| class_name.respond_to?(x) } -                    class_name +          coder = if [:load, :dump].all? { |x| class_name_or_coder.respond_to?(x) } +                    class_name_or_coder                    else -                    Coders::YAMLColumn.new(class_name) +                    Coders::YAMLColumn.new(class_name_or_coder)                    end            # merge new serialized attribute and create new hash to ensure that each class in inheritance hierarchy diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb index 76a61d492a..3b484a0d64 100644 --- a/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -233,13 +233,13 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase    def test_belongs_to_counter      debate = Topic.create("title" => "debate") -    assert_equal 0, debate.send(:read_attribute, "replies_count"), "No replies yet" +    assert_equal 0, debate.read_attribute("replies_count"), "No replies yet"      trash = debate.replies.create("title" => "blah!", "content" => "world around!") -    assert_equal 1, Topic.find(debate.id).send(:read_attribute, "replies_count"), "First reply created" +    assert_equal 1, Topic.find(debate.id).read_attribute("replies_count"), "First reply created"      trash.destroy -    assert_equal 0, Topic.find(debate.id).send(:read_attribute, "replies_count"), "First reply deleted" +    assert_equal 0, Topic.find(debate.id).read_attribute("replies_count"), "First reply deleted"    end    def test_belongs_to_counter_with_assigning_nil diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb index 952baaca36..38e93288e4 100644 --- a/activerecord/test/cases/attribute_methods_test.rb +++ b/activerecord/test/cases/attribute_methods_test.rb @@ -288,10 +288,10 @@ class AttributeMethodsTest < ActiveRecord::TestCase    def test_read_attribute      topic = Topic.new      topic.title = "Don't change the topic" -    assert_equal "Don't change the topic", topic.send(:read_attribute, "title") +    assert_equal "Don't change the topic", topic.read_attribute("title")      assert_equal "Don't change the topic", topic["title"] -    assert_equal "Don't change the topic", topic.send(:read_attribute, :title) +    assert_equal "Don't change the topic", topic.read_attribute(:title)      assert_equal "Don't change the topic", topic[:title]    end @@ -358,10 +358,10 @@ class AttributeMethodsTest < ActiveRecord::TestCase        super(attr_name).upcase      end -    assert_equal "STOP CHANGING THE TOPIC", topic.send(:read_attribute, "title") +    assert_equal "STOP CHANGING THE TOPIC", topic.read_attribute("title")      assert_equal "STOP CHANGING THE TOPIC", topic["title"] -    assert_equal "STOP CHANGING THE TOPIC", topic.send(:read_attribute, :title) +    assert_equal "STOP CHANGING THE TOPIC", topic.read_attribute(:title)      assert_equal "STOP CHANGING THE TOPIC", topic[:title]    end diff --git a/guides/source/3_0_release_notes.md b/guides/source/3_0_release_notes.md index dd81ec58f9..2d4be0cda7 100644 --- a/guides/source/3_0_release_notes.md +++ b/guides/source/3_0_release_notes.md @@ -294,7 +294,7 @@ NOTE. The old style `map` commands still work as before with a backwards compati  Deprecations  * The catch all route for non-REST applications (`/:controller/:action/:id`) is now commented out. -* Routes :path\_prefix no longer exists and :name\_prefix now automatically adds "\_" at the end of the given value. +* Routes `:path_prefix` no longer exists and `:name_prefix` now automatically adds "_" at the end of the given value.  More Information:  * [The Rails 3 Router: Rack it Up](http://yehudakatz.com/2009/12/26/the-rails-3-router-rack-it-up/) diff --git a/guides/source/3_2_release_notes.md b/guides/source/3_2_release_notes.md index ce811a583b..cdcde67869 100644 --- a/guides/source/3_2_release_notes.md +++ b/guides/source/3_2_release_notes.md @@ -187,7 +187,7 @@ Action Pack      Rails will use `layouts/single_car` when a request comes in `:show` action, and use `layouts/application` (or `layouts/cars`, if exists) when a request comes in for any other actions. -* `form\_for` is changed to use `#{action}\_#{as}` as the css class and id if `:as` option is provided. Earlier versions used `#{as}\_#{action}`. +* `form_for` is changed to use `#{action}_#{as}` as the css class and id if `:as` option is provided. Earlier versions used `#{as}_#{action}`.  * `ActionController::ParamsWrapper` on Active Record models now only wrap `attr_accessible` attributes if they were set. If not, only the attributes returned by the class method `attribute_names` will be wrapped. This fixes the wrapping of nested attributes by adding them to `attr_accessible`. diff --git a/guides/source/asset_pipeline.md b/guides/source/asset_pipeline.md index d688bb7b4e..d3dc790500 100644 --- a/guides/source/asset_pipeline.md +++ b/guides/source/asset_pipeline.md @@ -1041,6 +1041,14 @@ cache store.  config.assets.cache_store = :memory_store, { size: 32.megabytes }  ``` +To disable the assets cache store: + +```ruby +config.assets.configure do |env| +  env.cache = ActiveSupport::Cache.lookup_store(:null_store) +end +``` +  Adding Assets to Your Gems  -------------------------- diff --git a/guides/source/association_basics.md b/guides/source/association_basics.md index 5ec6ae0f21..df38bd7321 100644 --- a/guides/source/association_basics.md +++ b/guides/source/association_basics.md @@ -571,7 +571,7 @@ If you create an association some time after you build the underlying model, you  If you create a `has_and_belongs_to_many` association, you need to explicitly create the joining table. Unless the name of the join table is explicitly specified by using the `:join_table` option, Active Record creates the name by using the lexical order of the class names. So a join between customer and order models will give the default join table name of "customers_orders" because "c" outranks "o" in lexical ordering. -WARNING: The precedence between model names is calculated using the `<` operator for `String`. This means that if the strings are of different lengths, and the strings are equal when compared up to the shortest length, then the longer string is considered of higher lexical precedence than the shorter one. For example, one would expect the tables "paper\_boxes" and "papers" to generate a join table name of "papers\_paper\_boxes" because of the length of the name "paper\_boxes", but it in fact generates a join table name of "paper\_boxes\_papers" (because the underscore '\_' is lexicographically _less_ than 's' in common encodings). +WARNING: The precedence between model names is calculated using the `<` operator for `String`. This means that if the strings are of different lengths, and the strings are equal when compared up to the shortest length, then the longer string is considered of higher lexical precedence than the shorter one. For example, one would expect the tables "paper_boxes" and "papers" to generate a join table name of "papers_paper_boxes" because of the length of the name "paper_boxes", but it in fact generates a join table name of "paper_boxes_papers" (because the underscore '_' is lexicographically _less_ than 's' in common encodings).  Whatever the name, you must manually generate the join table with an appropriate migration. For example, consider these associations: diff --git a/guides/source/getting_started.md b/guides/source/getting_started.md index bafb75c668..36bbd1187c 100644 --- a/guides/source/getting_started.md +++ b/guides/source/getting_started.md @@ -99,7 +99,7 @@ ruby 2.0.0p353  ```  If you don't have Ruby installed have a look at -[ruby-lang.org](https://www.ruby-lang.org/en/downloads/) for possible ways to +[ruby-lang.org](https://www.ruby-lang.org/en/installation/) for possible ways to  install Ruby on your platform.  Many popular UNIX-like OSes ship with an acceptable version of SQLite3. Windows @@ -612,7 +612,7 @@ def create  end  ``` -The `render` method here is taking a very simple hash with a key of `text` and +The `render` method here is taking a very simple hash with a key of `plain` and  value of `params[:article].inspect`. The `params` method is the object which  represents the parameters (or fields) coming in from the form. The `params`  method returns an `ActiveSupport::HashWithIndifferentAccess` object, which @@ -1136,7 +1136,7 @@ The `method: :patch` option tells Rails that we want this form to be submitted  via the `PATCH` HTTP method which is the HTTP method you're expected to use to  **update** resources according to the REST protocol. -The first parameter of the `form_tag` can be an object, say, `@article` which would +The first parameter of `form_for` can be an object, say, `@article` which would  cause the helper to fill in the form with the fields of the object. Passing in a  symbol (`:article`) with the same name as the instance variable (`@article`) also  automagically leads to the same behavior. This is what is happening here. More details diff --git a/guides/source/security.md b/guides/source/security.md index 9603fb4a4d..15b28664b7 100644 --- a/guides/source/security.md +++ b/guides/source/security.md @@ -151,7 +151,7 @@ The most effective countermeasure is to _issue a new session identifier_ and dec  reset_session  ``` -If you use the popular RestfulAuthentication plugin for user management, add reset\_session to the SessionsController#create action. Note that this removes any value from the session, _you have to transfer them to the new session_. +If you use the popular RestfulAuthentication plugin for user management, add reset_session to the SessionsController#create action. Note that this removes any value from the session, _you have to transfer them to the new session_.  Another countermeasure is to _save user-specific properties in the session_, verify them every time a request comes in, and deny access, if the information does not match. Such properties could be the remote IP address or the user agent (the web browser name), though the latter is less user-specific. When saving the IP address, you have to bear in mind that there are Internet service providers or large organizations that put their users behind proxies. _These might change over the course of a session_, so these users will not be able to use your application, or only in a limited way. @@ -314,7 +314,7 @@ def sanitize_filename(filename)  end  ``` -A significant disadvantage of synchronous processing of file uploads (as the attachment\_fu plugin may do with images), is its _vulnerability to denial-of-service attacks_. An attacker can synchronously start image file uploads from many computers which increases the server load and may eventually crash or stall the server. +A significant disadvantage of synchronous processing of file uploads (as the attachment_fu plugin may do with images), is its _vulnerability to denial-of-service attacks_. An attacker can synchronously start image file uploads from many computers which increases the server load and may eventually crash or stall the server.  The solution to this is best to _process media files asynchronously_: Save the media file and schedule a processing request in the database. A second process will handle the processing of the file in the background.  | 
