Commit Graph

13913 Commits

Author SHA1 Message Date
Mehmet Emin İNAÇ
4f1ec3ac96 Fix misleading errors for has_one through relations 2015-07-22 00:51:23 +03:00
Sameer Rahmani
d763956ed9 Extra caller details added to ActiveRecord::RecordNotFound
ActiveRecord::RecordNotFound modified to store model name, primary_key
and id of the caller model. It allows the catcher of this exception to make
a better decision to what to do with it. For example consider this simple
example:

    class SomeAbstractController < ActionController::Base
      rescue_from ActiveRecord::RecordNotFound, with: :redirect_to_404

      private def redirect_to_404(e)
        return redirect_to(posts_url) if e.model == 'Post'
        raise
      end
    end
2015-07-21 19:19:14 +04:30
Roque Pinel
b184398b53 Deprecate and rename the keys for association restrict_dependent_destroy
Previously `has_one` and `has_many` associations were using the
`one` and `many` keys respectively. Both of these keys have special
meaning in I18n (they are considered to be pluralizations) so by
renaming them to `has_one` and `has_many` we make the messages more
explicit and most importantly they don't clash with linguistical
systems that need to validate translation keys (and their
pluralizations).

The `:'restrict_dependent_destroy.one'` key should be replaced with
`:'restrict_dependent_destroy.has_one'`, and
`:'restrict_dependent_destroy.many'` with
`:'restrict_dependent_destroy.has_many'`.

[Roque Pinel & Christopher Dell]
2015-07-20 23:19:43 -04:00
Jori Hardman
e975d7cd1a Ensure that microsecond precision is only used for version of mysql that support it. Fixes #19711 2015-07-20 15:30:10 -05:00
Sean Griffin
17b846004d Fix minor typo in test name 2015-07-20 09:22:30 -06:00
Roque Pinel
12b0b26df7 Fix state being carried over from previous transaction
This clears the transaction record state when the transaction finishes
with a `:committed` status.

Considering the following example where `name` is a required attribute.
Before we had `new_record?` returning `true` for a persisted record:

```ruby
  author = Author.create! name: 'foo'
  author.name = nil
  author.save        # => false
  author.new_record? # => true
```
2015-07-20 09:12:01 -06:00
Sean Griffin
c0ef95a1c6 Correctly ignore mark_for_destruction without autosave
As per the docs, `mark_for_destruction` should do nothing if `autosave`
is not set to true. We normally persist associations on a record no
matter what if the record is a new record, but we were always skipping
records which were `marked_for_destruction?`.

Fixes #20882
2015-07-20 09:00:00 -06:00
Sean Griffin
9bd6e39b0c Merge pull request #20949 from vngrs/missing_method_in_exception
Add missing method name to exception description
2015-07-20 08:39:48 -06:00
Mehmet Emin İNAÇ
cc54f6be15 fix doc about ActiveRecord::Transactions::ClassMethods#transaction [ci skip] 2015-07-20 11:11:24 +03:00
Mehmet Emin İNAÇ
1883f37742 Add missing method name to exception description 2015-07-20 10:58:59 +03:00
Sean Griffin
f91439d848 Merge pull request #20946 from schneems/schneems/let-it-go
Freeze string literals when not mutated.
2015-07-19 17:09:13 -06:00
schneems
5bb1d4d288 Freeze string literals when not mutated.
I wrote a utility that helps find areas where you could optimize your program using a frozen string instead of a string literal, it's called [let_it_go](https://github.com/schneems/let_it_go). After going through the output and adding `.freeze` I was able to eliminate the creation of 1,114 string objects on EVERY request to [codetriage](codetriage.com). How does this impact execution?

To look at memory:

```ruby
require 'get_process_mem'

mem = GetProcessMem.new
GC.start
GC.disable
1_114.times { " " }
before = mem.mb

after = mem.mb
GC.enable
puts "Diff: #{after - before} mb"

```

Creating 1,114 string objects results in `Diff: 0.03125 mb` of RAM allocated on every request. Or 1mb every 32 requests.

To look at raw speed:

```ruby
require 'benchmark/ips'

number_of_objects_reduced = 1_114

Benchmark.ips do |x|
  x.report("freeze")    { number_of_objects_reduced.times { " ".freeze } }
  x.report("no-freeze") { number_of_objects_reduced.times { " " } }
end
```

We get the results

```
Calculating -------------------------------------
              freeze     1.428k i/100ms
           no-freeze   609.000  i/100ms
-------------------------------------------------
              freeze     14.363k (± 8.5%) i/s -     71.400k
           no-freeze      6.084k (± 8.1%) i/s -     30.450k
```

Now we can do some maths:

```ruby
ips = 6_226k # iterations / 1 second
call_time_before = 1.0 / ips # seconds per iteration 

ips = 15_254 # iterations / 1 second
call_time_after = 1.0 / ips # seconds per iteration 

diff = call_time_before - call_time_after

number_of_objects_reduced * diff * 100

# => 0.4530373333993266 miliseconds saved per request
```

So we're shaving off 1 second of execution time for every 220 requests. 

Is this going to be an insane speed boost to any Rails app: nope. Should we merge it: yep. 

p.s. If you know of a method call that doesn't modify a string input such as [String#gsub](b0e2da69f0/lib/let_it_go/core_ext/string.rb (L37)) please [give me a pull request to the appropriate file](b0e2da69f0/lib/let_it_go/core_ext/string.rb (L37)), or open an issue in LetItGo so we can track and freeze more strings. 

Keep those strings Frozen

![](https://www.dropbox.com/s/z4dj9fdsv213r4v/let-it-go.gif?dl=1)
2015-07-19 17:45:10 -05:00
Sean Griffin
8cd1d5a41c Fix the test that was broken by #16445 rather than deleting it
Since the counter cache was properly being updated, the model became
stale. Simply reloading the model before attempting to destroy is
sufficient for this case. I believe this is enough of an edge case to be
a valid change to the tests, even though it represents a potential
breaking change.
2015-07-19 15:52:31 -06:00
Stefan Kanev
0ed096ddf5 Fix counter_cache for polymorphic associations
Also removes a false positive test that depends on the fixed bug:

At this time, counter_cache does not work with polymorphic relationships
(which is a bug). The test was added to make sure that no
StaleObjectError is raised when the car is destroyed. No such error is
currently raised because the lock version is not incremented by
appending a wheel to the car.

Furthermore, `assert_difference` succeeds because `car.wheels.count`
does not check the counter cache, but the collection size. The test will
fail if it is replaced with `car.wheels_count || 0`.
2015-07-19 15:52:29 -06:00
Abdelkader Boudih
fac744f87e Merge pull request #20924 from andrii/master
[ci skip] Fix typo in #any? RDoc
2015-07-19 09:27:49 +01:00
Sean Griffin
3f1c5d39c0 Merge pull request #20932 from twalpole/collection_association_parameters
Ensure that 'ActionController::Parameters' can still be passed to AR …
2015-07-18 13:21:06 -05:00
Thomas Walpole
b5d4dd47de Ensure that 'ActionController::Parameters' can still be passed to AR for collection associations 2015-07-18 08:23:52 -07:00
Sean Griffin
7550f0a016 Ensure cyclic associations w/ autosave don't cause duplicate errors
This code is so fucked. Things that cause this bug not to replicate:

- Defining the validation before the association (we end up calling
  `uniq!` on the errors in the autosave validation)
- Adding `accepts_nested_attributes_for` (I have no clue why. The only
  thing it does that should affect this is adds `autosave: true` to the
  inverse reflection, and doing that manually doesn't fix this).

This solution is a hack, and I'm almost certain there's a better way to
go about it, but this shouldn't cause a huge hit on validation times,
and is the simplest way to get it done.

Fixes #20874.
2015-07-18 10:30:58 -04:00
Sean Griffin
68af636182 Ensure that ActionController::Parameters can still be passed to AR
Since nested hashes are also instances of
`ActionController::Parameters`, and we're explicitly looking to work
with a hash for nested attributes, this caused breakage in several
points.

This is the minimum viable fix for the issue (and one that I'm not
terribly fond of). I can't think of a better place to handle this at the
moment. I'd prefer to use some sort of solution that doesn't special
case AC::Parameters, but we can't use something like `to_h` or `to_a`
since `Enumerable` adds both.

While I've added a trivial test case for verifying this fix in
isolation, we really need better integration coverage to prevent
regressions like this in the future. We don't actually have a lot of
great places for integration coverage at the moment, so I'm deferring it
for now.

Fixes #20922.
2015-07-18 08:44:24 -04:00
Andrii Ponomarov
a8e11ff528 [ci skip] Fix typo in #any? RDoc 2015-07-17 21:03:49 -04:00
Prem Sichanugrist
b5b8979621 Silence deprecation warning from force reload
We deprecate the support for passing an argument to force reload in
6eae366d0d2e5d5211eeaf955f56bd1dc6836758. That led to several
deprecation warning when running Active Record test suite.

This commit silence the warnings by properly calling `#reload` on the
association proxy or on the association object instead. However, there
are several places that `ActiveSupport::Deprecation.silence` are used as
those tests actually tests the force reload functionality and will be
removed once `master` is targeted next minor release (5.1).
2015-07-16 16:06:26 -04:00
Prem Sichanugrist
6eae366d0d Deprecate force association reload by passing true
This is to simplify the association API, as you can call `reload` on the
association proxy or the parent object to get the same result.

For collection association, you can call `#reload` on association proxy
to force a reload:

    @user.posts.reload   # Instead of @user.posts(true)

For singular association, you can call `#reload` on the parent object to
clear its association cache then call the association method:

    @user.reload.profile   # Instead of @user.profile(true)

Passing a truthy argument to force association to reload will be removed
in Rails 5.1.
2015-07-15 14:07:45 -04:00
Rafael Mendonça França
64c1264419 Merge pull request #20887 from tgxworld/ar_callbacks
Revert "Revert "Reduce allocations when running AR callbacks.""
2015-07-15 14:26:09 -03:00
Guo Xiang Tan
beb07fbfae Revert "Revert "Reduce allocations when running AR callbacks.""
This reverts commit bdc1d329d4eea823d07cf010064bd19c07099ff3.

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: 'bdc1d329d4eea823d07cf010064bd19c07099ff3'
  gem 'rails', github: 'rails/rails', ref: 'd2876141d08341ec67cf6a11a073d1acfb920de7'
  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}"
```
2015-07-16 01:02:15 +08:00
Jerry D'Antonio
284a9ba8ec Replaced ActiveSupport::Concurrency::Latch with concurrent-ruby.
The concurrent-ruby gem is a toolset containing many concurrency
utilities. Many of these utilities include runtime-specific
optimizations when possible. Rather than clutter the Rails codebase with
concurrency utilities separate from the core task, such tools can be
superseded by similar tools in the more specialized gem. This commit
replaces `ActiveSupport::Concurrency::Latch` with
`Concurrent::CountDownLatch`, which is functionally equivalent.
2015-07-13 15:44:21 -04:00
Rafael Mendonça França
1b4399dfe7 Fix regression caused by a01d164b
When preload is used in a default scope the preload_values were
returning nested arrays and causing the preloader to fail because it
doesn't know how to deal with nested arrays. So before calling preload!
we need to splat the arguments.

This is not needed to includes because it flatten its arguments.
2015-07-07 13:40:50 -03:00
Dmitry Zudochkin
3d5580fa85 Update CHANGELOG.md 2015-07-07 13:03:44 +03:00
Victor Costan
fccb076bd8 Add test proving that accepts_nested_attributes_for is secure against ID tampering attacks. 2015-07-07 03:04:21 -04:00
Jon Atack
64401610b5 [skip ci] #distinct instead of #uniq
as #uniq will be removed from Rails 5.0 as per the Active Support
exception raised:

ActiveSupport::DeprecationException: DEPRECATION WARNING: uniq is
deprecated and will be removed from Rails 5.0 (use distinct instead).
2015-07-03 11:11:59 +02:00
eileencodes
cc7ef0cf19 Fix spelling of Thoughtleadering
Not much of a thought leader if I can't spell it correctly 😉
2015-07-02 15:48:47 -04:00
eileencodes
eff3a3178e Use default model enum in fixtures if not defined
After 908cfef was introduced fixtures that did not set an enum would
return nil instead of the default enum value.

The fixtures should assume the default if a different enum is not
defined.

The change checks first if the enum is defined in the fixture before
setting it based on the fixture.
2015-07-02 15:42:52 -04:00
Sean Griffin
bc6ac8609c Correct through associations using scopes
The changes introduced to through associations in c80487eb were quite
interesting. Changing `relation.merge!(scope)` to `relation =
relation.merge(scope)` should in theory never cause any changes in
behavior. The subtle breakage led to a surprising conclusion.

The old code wasn't doing anything! Since `merge!` calls
`instance_exec` when given a proc, and most scopes will look something
like `has_many :foos, -> { where(foo: :bar) }`, if we're not capturing
the return value, it's a no-op. However, removing the `merge` causes
`unscope` to break.

While we're merging in the rest of the chain elsewhere, we were never
merging in `unscope` values, causing a breakage on associations where a
default scope was being unscoped in an association scope (yuk!). This is
subtly related to #20722, since it appears we were previously relying on
this mutability.

Fixes #20721.
Fixes #20727.
2015-06-30 10:00:30 -07:00
Yves Senn
f55c60f5ae follow-up to 2183caa, always reenable the task. #20743 2015-06-30 16:44:34 +02:00
Yves Senn
2183caa24a dump_schema_after_migration applies migration tasks other than db:migrate
Closes #20743.

The task `db:_dump` now only dumps the schema if
`ActiveRecord::Base.dump_schema_after_migration` is true. This has
effects:

- `db:migrate:up`
- `db:migrate:down`
- `db:forward`
- `db:rollback`
2015-06-30 16:36:03 +02:00
Yves Senn
5aee168e73 docs, nodoc NullPreloader and AlreadyLoaded.
These classes are part of Active Record Preloader, which is not part of
the public API.
2015-06-29 14:47:11 +02:00
Sean Griffin
6a6c4c4591 Revert the behavior of association names and where to be closer to 4.2
With this change, we will always assume the association name is the same
as the table it's referencing. This is subtly different than treating
the hash key passed to `where` as the table name, as it still allows the
class referenced by the association to provide additional type
information.

After exploring several possible solutions to the ambiguity problem, I
do not think there is a short term answer that will maintain backwards
compatibility.

This change will make it so the following code does not work:

    class User
      has_many :approved_posts, -> { where(approved: true) }, class_name: "Post"
    end

    User.where(approved_posts: { id: 1 })

But prevents potential ambiguity and collision as demonstrated in [this
gist](https://gist.github.com/senny/1ae4d8ea7b0e269ed7a0).

Unfortunately, truely solving this requires significantly
re-architecting this code, so that what is currently represented as an
`Arel::Attribute` is instead another data structure that also references
the association it is representing, so we can identify the proper table
name for aliasing when we construct the final tree.

While I'd still like to accomplish that in the long run, I don't think
I'll be able to get there in time for Rails 5 (since I'm not full time
OSS any more, and this is several weeks worth of work). I'm hoping to
achieve this for Rails 5.1.

Fixes #20308
2015-06-27 18:14:38 -06:00
Rafael Mendonça França
261a8e1c4b Merge pull request #20607 from cmtonkinson/update-console-colors
More granular console SQL coloration
2015-06-27 02:13:53 -03:00
Rafael Mendonça França
9f94f73743 Merge pull request #20699 from vngrs/foreign_key_with_table_name_suffix_and_prefix
Add table name prefix and suffix support for foreign keys
2015-06-27 01:50:51 -03:00
Rafael Mendonça França
859c8c3f67 Merge pull request #20018 from sikachu/change-column-default-recorder
Add reversible syntax for change_column_default
2015-06-27 01:45:22 -03:00
Prem Sichanugrist
03f35fc439 Update .pluck documentation on uniq
This is to show users that they can chain `.uniq` and `.pluck` to get
the `DISTINCT column` result. They don't have to do `DISTINCT column`
themselves.
2015-06-26 16:34:42 -04:00
Prem Sichanugrist
a4128725f5 Add reversible syntax for change_column_default
Passing `:from` and `:to` to `change_column_default` makes this command
reversible as user has defined its previous state.

So, instead of having the migration command as:

    change_column_default(:posts, :state, "draft")

They can write it as:

    change_column_default(:posts, :state, from: nil, to: "draft")
2015-06-26 16:25:13 -04:00
Sean Griffin
0bee4100f1 Merge pull request #20677 from jmondo/decimal-default-string
Display decimal defaults as strings to keep precision
2015-06-25 19:06:48 -06:00
David Heinemeier Hansson
5f5e6d9249 Add pending test for the great-grandparent touching bug from #19324 2015-06-25 14:23:06 +02:00
Mehmet Emin İNAÇ
c26b9148e5 Add table name prefix and suffix support to add_foreign_key and remove_foreign_key methods
fix tests
2015-06-25 14:49:08 +03:00
John Gesimondo
4f58c501cf Display decimal defaults as strings to keep precision 2015-06-23 14:38:00 -07:00
Chris Tonkinson
f5d8dd6d8f More granular console SQL coloration
This new coloration approach makes it easier to scan the rails console
for specific types of activity with more fine-grained visual cues.

Virtual terminal ANSI color escape codes are used when displaying SQL
statements in the rails console. The former implementation alternates
line prefix information (including the statement name and execution
latency) between CYAN and MAGENTA. This visually differentiates any SQL
statements in the log and is useful for quickly scanning for database
activity.

While a great idea and a solid foundation, alternating between just two
colors on an even/odd basis (much like striping an HTML table) can be
improved upon.

This patch replaces the even/odd striping with a more comprehensive
scheme that applies coloration based on the type of statement being
run. Every statement logged has its prefix (name and latency) colored
white (as the statement body was previously). The statement body is now
colored according to the nature of the statement:

  - INSERT statements are GREEN (symbolic of creation or genesis)
  - SELECT statements are BLUE (typically used for informational
    displays, as SELECT statements do not normally have side-effects)
  - DELETE statements are RED (commonly used to indicate the danger of
    a destructive action)
  - UPDATE statements are YELLOW (it's like a less extreme RED :P)
  - TRANSACTION statements are CYAN (arbitrary)
  - and any other statements are MAGENTA (again, arbitrary)
2015-06-23 14:01:28 -04:00
Robin Dupret
e09129c94c A few documentation fixes [ci skip] 2015-06-23 17:55:37 +02:00
Yves Senn
de0a2a49a8 Merge pull request #20673 from aditya-kapoor/correct-preload-doc
[ci skip] correct for ActiveRecord::Associations::Preloader
2015-06-23 16:02:45 +02:00
Yves Senn
352b18d22a docs, add missing closing bracket. [ci skip] 2015-06-23 15:51:42 +02:00
Aditya Kapoor
c5c0ace39c [ci skip] correct for ActiveRecord::Associations::Preloader: 2015-06-23 19:02:39 +05:30