1. 30 3月, 2018 1 次提交
  2. 15 12月, 2017 1 次提交
  3. 24 10月, 2017 1 次提交
  4. 11 10月, 2017 1 次提交
  5. 20 7月, 2017 1 次提交
  6. 02 7月, 2017 1 次提交
  7. 01 7月, 2017 1 次提交
  8. 24 12月, 2016 1 次提交
  9. 22 12月, 2016 1 次提交
  10. 02 11月, 2016 1 次提交
    • S
      Deprecate the behavior of AR::Dirty inside of after_(create|update|save) callbacks · 16ae3db5
      Sean Griffin 提交于
      We pretty frequently get bug reports that "dirty is broken inside of
      after callbacks". Intuitively they are correct. You'd expect
      `Model.after_save { puts changed? }; model.save` to do the same thing as
      `model.save; puts model.changed?`, but it does not.
      
      However, changing this goes much farther than just making the behavior
      more intuitive. There are a _ton_ of places inside of AR that can be
      drastically simplified with this change. Specifically, autosave
      associations, timestamps, touch, counter cache, and just about anything
      else in AR that works with callbacks have code to try to avoid "double
      save" bugs which we will be able to flat out remove with this change.
      
      We introduce two new sets of methods, both with names that are meant to
      be more explicit than dirty. The first set maintains the old behavior,
      and their names are meant to center that they are about changes that
      occurred during the save that just happened. They are equivalent to
      `previous_changes` when called outside of after callbacks, or once the
      deprecation cycle moves.
      
      The second set is the new behavior. Their names imply that they are
      talking about changes from the database representation. The fact that
      this is what we really care about became clear when looking at
      `BelongsTo.touch_record` when tests were failing. I'm unsure that this
      set of methods should be in the public API. Outside of after callbacks,
      they are equivalent to the existing methods on dirty.
      
      Dirty itself is not deprecated, nor are the methods inside of it. They
      will only emit the warning when called inside of after callbacks. The
      scope of this breakage is pretty large, but the migration path is
      simple. Given how much this can improve our codebase, and considering
      that it makes our API more intuitive, I think it's worth doing.
      16ae3db5
  11. 07 8月, 2016 1 次提交
  12. 06 5月, 2016 1 次提交
  13. 05 5月, 2016 2 次提交
  14. 13 2月, 2016 1 次提交
  15. 16 12月, 2015 1 次提交
  16. 07 12月, 2015 1 次提交
    • Y
      Typo correction · bcf89f44
      Yves Siegrist 提交于
      In the doc the `dependent` option was set with: `dependent: destroy`.
      This is not working because destroy would call the method of the activerecord::base object.
      
      The right way is: `dependent: :destroy`
      bcf89f44
  17. 14 10月, 2015 2 次提交
    • Y
      applies new doc guidelines to Active Record. · 428d47ad
      Yves Senn 提交于
      The focus of this change is to make the API more accessible.
      References to method and classes should be linked to make it easy to
      navigate around.
      
      This patch makes exzessiv use of `rdoc-ref:` to provide more readable
      docs. This makes it possible to document `ActiveRecord::Base#save` even
      though the method is within a separate module
      `ActiveRecord::Persistence`. The goal here is to bring the API closer to
      the actual code that you would write.
      
      This commit only deals with Active Record. The other gems will be
      updated accordingly but in different commits. The pass through Active
      Record is not completely finished yet. A follow up commit will change
      the spots I haven't yet had the time to update.
      
      /cc @fxn
      428d47ad
    • Y
      715d9bd4
  18. 12 8月, 2015 1 次提交
  19. 24 7月, 2015 1 次提交
    • S
      `destroy` shouldn't raise when child associations fail to save · d937a117
      Sean Griffin 提交于
      Deep down in the association internals, we're calling `destroy!` rather
      than `destroy` when handling things like `dependent` or autosave
      association callbacks. Unfortunately, due to the structure of the code
      (e.g. it uses callbacks for everything), it's nearly impossible to pass
      whether to call `destroy` or `destroy!` down to where we actually need
      it.
      
      As such, we have to do some legwork to handle this. Since the callbacks
      are what actually raise the exception, we need to rescue it in
      `ActiveRecord::Callbacks`, rather than `ActiveRecord::Persistence` where
      it matters. (As an aside, if this code wasn't so callback heavy, it
      would handling this would likely be as simple as changing `destroy` to
      call `destroy!` instead of the other way around).
      
      Since we don't want to lose the exception when `destroy!` is called (in
      particular, we don't want the value of the `record` field to change to
      the parent class), we have to do some additional legwork to hold onto it
      where we can use it.
      
      Again, all of this is ugly and there is definitely a better way to do
      this. However, barring a much more significant re-architecting for what
      I consider to be a reletively minor improvement, I'm willing to take
      this small hit to the flow of this code (begrudgingly).
      d937a117
  20. 16 7月, 2015 1 次提交
    • G
      Revert "Revert "Reduce allocations when running AR callbacks."" · beb07fbf
      Guo Xiang Tan 提交于
      This reverts commit bdc1d329.
      
      Before:
      Calculating -------------------------------------
                              22.000  i/100ms
      -------------------------------------------------
                              229.700  (± 0.4%) i/s -      1.166k
      Total Allocated Object: 9939
      
      After:
      Calculating -------------------------------------
                              24.000  i/100ms
      -------------------------------------------------
                              246.443  (± 0.8%) i/s -      1.248k
      Total Allocated Object: 7939
      
      ```
      begin
        require 'bundler/inline'
      rescue LoadError => e
        $stderr.puts 'Bundler version 1.10 or later is required. Please update your Bundler'
        raise e
      end
      
      gemfile(true) do
        source 'https://rubygems.org'
        # gem 'rails', github: 'rails/rails', ref: 'bdc1d329'
        gem 'rails', github: 'rails/rails', ref: 'd2876141'
        gem 'arel', github: 'rails/arel'
        gem 'sqlite3'
        gem 'benchmark-ips'
      end
      
      require 'active_record'
      require 'benchmark/ips'
      
      ActiveRecord::Base.establish_connection('sqlite3::memory:')
      
      ActiveRecord::Migration.verbose = false
      
      ActiveRecord::Schema.define do
        create_table :users, force: true do |t|
          t.string :name, :email
          t.boolean :admin
          t.timestamps null: false
        end
      end
      
      class User < ActiveRecord::Base
        default_scope { where(admin: true) }
      end
      
      admin = true
      
      1000.times do
        attributes = {
          name: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
          email: "foobar@email.com",
          admin: admin
        }
      
        User.create!(attributes)
      
        admin = !admin
      end
      
      GC.disable
      
      Benchmark.ips(5, 3) do |x|
        x.report { User.all.to_a }
      end
      
      key =
        if RUBY_VERSION < '2.2'
          :total_allocated_object
        else
          :total_allocated_objects
        end
      
      before = GC.stat[key]
      User.all.to_a
      after = GC.stat[key]
      puts "Total Allocated Object: #{after - before}"
      ```
      beb07fbf
  21. 20 5月, 2015 1 次提交
  22. 22 3月, 2015 1 次提交
  23. 16 1月, 2015 1 次提交
    • S
      Add support for bidirectional destroy dependencies · d5bf649a
      Seb Jacobs 提交于
      Prior to this commit if you defined a bidirectional relationship
      between two models with destroy dependencies on both sides, a call to
      `destroy` would result in an infinite callback loop.
      
      Take the following relationship.
      
          class Content < ActiveRecord::Base
            has_one :content_position, dependent: :destroy
          end
      
          class ContentPosition < ActiveRecord::Base
            belongs_to :content, dependent: :destroy
          end
      
      Calling `Content#destroy` or `ContentPosition#destroy` would result in
      an infinite callback loop.
      
      This commit changes the behaviour of `ActiveRecord::Callbacks#destroy`
      so that it guards against subsequent callbacks.
      
      Thanks to @zetter for demonstrating the issue with failing tests[1].
      
      [1] rails#13609
      d5bf649a
  24. 03 1月, 2015 1 次提交
    • C
      Deprecate `false` as the way to halt AR callbacks · bb78af73
      claudiob 提交于
      Before this commit, returning `false` in an ActiveRecord `before_` callback
      such as `before_create` would halt the callback chain.
      
      After this commit, the behavior is deprecated: will still work until
      the next release of Rails but will also display a deprecation warning.
      
      The preferred way to halt a callback chain is to explicitly `throw(:abort)`.
      bb78af73
  25. 28 12月, 2014 1 次提交
  26. 26 10月, 2014 1 次提交
  27. 29 9月, 2014 1 次提交
    • P
      Reduce allocations when running AR callbacks. · 796cab45
      Pete Higgins 提交于
      Inspired by @tenderlove's work in
      c363fff2, this reduces the number of
      strings allocated when running callbacks for ActiveRecord instances. I
      measured that using this script:
      
      ```
      require 'objspace'
      require 'active_record'
      require 'allocation_tracer'
      
      ActiveRecord::Base.establish_connection adapter: "sqlite3",
                                              database: ":memory:"
      
      ActiveRecord::Base.connection.instance_eval do
        create_table(:articles) { |t| t.string :name }
      end
      
      class Article < ActiveRecord::Base; end
      a = Article.create name: "foo"
      a = Article.find a.id
      
      N = 10
      result = ObjectSpace::AllocationTracer.trace do
        N.times { Article.find a.id }
      end
      
      result.sort.each do |k,v|
        p k => v
      end
      puts "total: #{result.values.map(&:first).inject(:+)}"
      ```
      
      When I run this against master and this branch I get this output:
      
      ```
      pete@balloon:~/projects/rails/activerecord$ git checkout master
      M Gemfile
      Switched to branch 'master'
      pete@balloon:~/projects/rails/activerecord$ bundle exec ruby benchmark_allocation_with_callback_send.rb > allocations_before
      pete@balloon:~/projects/rails/activerecord$ git checkout remove-dynamic-send-on-built-in-callbacks
      M Gemfile
      Switched to branch 'remove-dynamic-send-on-built-in-callbacks'
      pete@balloon:~/projects/rails/activerecord$ bundle exec ruby benchmark_allocation_with_callback_send.rb > allocations_after
      pete@balloon:~/projects/rails/activerecord$ diff allocations_before allocations_after
      39d38
      <
      {["/home/pete/projects/rails/activesupport/lib/active_support/callbacks.rb",
      81]=>[40, 0, 0, 0, 0, 0]}
      42c41
      < total: 630
      ---
      > total: 590
      
      ```
      
      In addition to this, there are two micro-optimizations present:
      
      * Using `block.call if block` vs `yield if block_given?` when the block was being captured already.
      
      ```
      pete@balloon:~/projects$ cat benchmark_block_call_vs_yield.rb
      require 'benchmark/ips'
      
      def block_capture_with_yield &block
        yield if block_given?
      end
      
      def block_capture_with_call &block
        block.call if block
      end
      
      def no_block_capture
        yield if block_given?
      end
      
      Benchmark.ips do |b|
        b.report("block_capture_with_yield") { block_capture_with_yield }
        b.report("block_capture_with_call") { block_capture_with_call }
        b.report("no_block_capture") { no_block_capture }
      end
      pete@balloon:~/projects$ ruby benchmark_block_call_vs_yield.rb
      Calculating -------------------------------------
      block_capture_with_yield
                              124979 i/100ms
      block_capture_with_call
                              138340 i/100ms
          no_block_capture    136827 i/100ms
      -------------------------------------------------
      block_capture_with_yield
                            5703108.9 (±2.4%) i/s -   28495212 in   4.999368s
      block_capture_with_call
                            6840730.5 (±3.6%) i/s -   34169980 in   5.002649s
          no_block_capture  5821141.4 (±2.8%) i/s -   29144151 in   5.010580s
      ```
      
      * Defining and calling methods instead of using send.
      
      ```
      pete@balloon:~/projects$ cat benchmark_method_call_vs_send.rb
      require 'benchmark/ips'
      
      class Foo
        def tacos
          nil
        end
      end
      
      my_foo = Foo.new
      
      Benchmark.ips do |b|
        b.report('send') { my_foo.send('tacos') }
        b.report('call') { my_foo.tacos }
      end
      pete@balloon:~/projects$ ruby benchmark_method_call_vs_send.rb
      Calculating -------------------------------------
                      send     97736 i/100ms
                      call    151142 i/100ms
      -------------------------------------------------
                      send  2683730.3 (±2.8%) i/s -   13487568 in   5.029763s
                      call  8005963.9 (±2.7%) i/s -   40052630 in   5.006604s
      ```
      
      The result of this is making typical ActiveRecord operations slightly faster:
      
      https://gist.github.com/phiggins/e46e51dcc7edb45b5f98
      796cab45
  28. 20 2月, 2014 1 次提交
  29. 03 12月, 2013 1 次提交
    • J
      Fix ActiveRecord::Callbacks sample code [ci skip] · edd93a53
      joker1007 提交于
      Callback caller class uses `after_initialize`,
      but Callback callee defines `after_find`.
      
      Current sample code causes following error.
      
        NoMethodError: undefined method `after_initialize' for #<EncryptionWrapper:0x007fe4931fa5c0>
      edd93a53
  30. 09 10月, 2013 1 次提交
  31. 21 4月, 2013 1 次提交
  32. 04 1月, 2013 1 次提交
  33. 09 11月, 2012 1 次提交
  34. 22 10月, 2012 1 次提交
  35. 21 10月, 2012 1 次提交
  36. 20 10月, 2012 1 次提交
  37. 20 6月, 2012 1 次提交
  38. 16 6月, 2012 1 次提交