Commit Graph

14399 Commits

Author SHA1 Message Date
Aaron Patterson 24b068bea1
Speed up partial rendering by caching "variable" calculation
This commit speeds up rendering partials by caching the variable name
calculation on the template.  The variable name is based on the "virtual
path" used for looking up the template.  The same virtual path
information lives on the template, so we can just ask the cached
template object for the variable.

This benchmark takes a couple files, so I'll cat them below:

```
[aaron@TC ~/g/r/actionview (speed-up-partials)]$ cat render_benchmark.rb
require "benchmark/ips"
require "action_view"
require "action_pack"
require "action_controller"

class TestController < ActionController::Base
end

TestController.view_paths = [File.expand_path("test/benchmarks")]
controller_view = TestController.new.view_context

result = Benchmark.ips do |x|
  x.report("render") do
    controller_view.render("many_partials")
  end
end
[aaron@TC ~/g/r/actionview (speed-up-partials)]$ cat test/benchmarks/test/_many_partials.html.erb
Looping:
<ul>
<% 100.times do |i| %>
  <%= render partial: "list_item", locals: { i: i } %>
<% end %>
</ul>
[aaron@TC ~/g/r/actionview (speed-up-partials)]$ cat test/benchmarks/test/_list_item.html.erb
<li>Number: <%= i %></li>
```

Benchmark results (master):

```
[aaron@TC ~/g/r/actionview (master)]$ be ruby render_benchmark.rb
Warming up --------------------------------------
              render    41.000  i/100ms
Calculating -------------------------------------
              render    424.269  (± 3.5%) i/s -      2.132k in   5.031455s
```

Benchmark results (this branch):

```
[aaron@TC ~/g/r/actionview (speed-up-partials)]$ be ruby render_benchmark.rb
Warming up --------------------------------------
              render    50.000  i/100ms
Calculating -------------------------------------
              render    521.862  (± 3.8%) i/s -      2.650k in   5.085885s
```
2019-02-05 15:24:21 -08:00
Ryuta Kamizono 0f3e8e1ebb Relation no longer respond to Arel methods
This follows up d97980a16d.
2019-02-06 04:58:45 +09:00
Ryuta Kamizono 2935d07569 Chaining named scope is no longer leaking to class level querying methods
Active Record uses `scoping` to delegate to named scopes from relations
for propagating the chaining source scope. It was needed to restore the
source scope in named scopes, but it was caused undesired behavior that
pollute all class level querying methods.

Example:

```ruby
class Topic < ActiveRecord::Base
  scope :toplevel, -> { where(parent_id: nil) }
  scope :children, -> { where.not(parent_id: nil) }
  scope :has_children, -> { where(id: Topic.children.select(:parent_id)) }
end

# Works as expected.
Topic.toplevel.where(id: Topic.children.select(:parent_id))

# Doesn't work due to leaking `toplevel` to `Topic.children`.
Topic.toplevel.has_children
```

Since #29301, the receiver in named scopes has changed from the model
class to the chaining source scope, so the polluting class level
querying methods is no longer required for that purpose.

Fixes #14003.
2019-02-06 00:37:08 +09:00
Ryuta Kamizono eec3e28a1a
Merge pull request #35127 from bogdan/counter-cache-loading
Bugfix association loading behavior when counter cache is zero
2019-02-05 20:32:37 +09:00
Bogdan Gusiev f1b64dff47 Bugfix association loading behavior when counter cache is zero 2019-02-05 11:58:59 +02:00
Aaron Patterson 3cace9eac9
Merge pull request #35154 from sponomarev/chore/sqlite1.4
Relax sqlite3 version dependency
2019-02-04 13:31:44 -08:00
Rafael Mendonça França cc2d614e63
Improve performance of blank? and present? in an ActiveRecord::Base instance
With this benchmark:

    require "bundler/setup"

    require "active_record"
    require "benchmark/ips"

    # This connection will do for database-independent bug reports.
    ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")

    ActiveRecord::Schema.define do
      create_table :posts, force: true do |t|
      end
    end

    class Post < ActiveRecord::Base
    end

    new_post = Post.new

    Benchmark.ips do |b|
      b.report("present?") do
        new_post.present?
      end

      b.report("blank?") do
        new_post.blank?
      end
    end

Before:

    Warming up --------------------------------------
                present?    52.147k i/100ms
                  blank?    53.077k i/100ms
    Calculating -------------------------------------
                present?    580.184k (±21.8%) i/s -      2.555M in   5.427085s
                  blank?    601.537k (± 9.2%) i/s -      2.972M in   5.003503s

After:

    Warming up --------------------------------------
                present?   378.235k i/100ms
                  blank?   375.476k i/100ms
    Calculating -------------------------------------
                present?     17.381M (± 7.5%) i/s -     86.238M in   5.001815s
                  blank?     17.877M (± 6.4%) i/s -     88.988M in   5.004634s

This improvement is mostly because those methods were hitting
`method_missing` on a lot of levels to be able to return the value.

To avoid all this stack walking we are short-circuiting those methods.

Closes #35059.
2019-02-04 15:56:47 -05:00
Sergey Ponomarev 2a29202288
Relax sqlite3 version dependency 2019-02-04 15:21:40 -05:00
Eileen M. Uchitelle 7d85d3847e
Merge pull request #35089 from eileencodes/fix-query-cache-for-database-switching
Invalidate all query caches for current thread
2019-02-04 08:46:10 -05:00
Eileen M. Uchitelle f4aed53e44
Merge pull request #35132 from eileencodes/allow-application-to-change-handler-names
Add ability to change the names of the default handlers
2019-02-04 08:45:48 -05:00
Gannon McGibbon 00f7dbab75
Merge pull request #35105 from olivierlacan/document-table-foreign-key
Hint at advanced options for foreign_key
2019-02-02 16:08:55 -05:00
Eileen Uchitelle 183c0eb472 Invalidate query cache for all connections in the current thread
This change ensures that all query cahces are cleared across all
connections per handler for the current thread so if you write on one
connection the read will have the query cache cleared.
2019-02-01 16:05:25 -05:00
Eileen Uchitelle 8d32346cde Add ability to change the names of the default handlers
When I wrote the `connected_to` and `connects_to` API's I wrote them
with the idea in mind that it didn't really matter what the
handlers/roles were called as long as those connecting to the roles knew
which one wrote and which one read.

With the introduction of the middleware Rails begins to assume it's
`writing` and `reading` and there's no room for other roles. At GitHub
we've been using this method for a long time so we have a ton of legacy
code that uses different handler names `default` and `readonly`. We
could rename all our code but I think this is better for a few reasons:

- Legacy apps that have been using multiple databases for a long time
  can have an eaiser time switching.
- If we later find this to cause more issues than it's worth we can
  easily deprecate.
- We won't force old apps to rewrite the resolver middleware just to use
  a different handler.

Adding the writing_role/reading_role required that I move the code that
creates the first handler for writing to the railtie. If I didn't move
this the core class would assign the handler before I was able to assign
a new one in my configuration and I'd end up with 3 handlers instead of
2.
2019-02-01 14:11:35 -05:00
Eileen M. Uchitelle caf8dbc159
Merge pull request #35130 from rails/move-delay-to-options-argument
Refactor options for database selector middleware
2019-02-01 13:53:34 -05:00
Rafael França bc0cad0690
Merge pull request #35082 from Shopify/eagerly-materialize-test-transactions
Eagerly materialize the fixtures transaction
2019-02-01 13:41:44 -05:00
Eileen Uchitelle 31f205234a Refactor options for middleware
Right now we only have one option that's supported, the delay. However I
can see us supporting other options in the future.

This PR refactors the options to get passed into the resolver so whether
you're using middleware or using the config options you can pass options
to the resolver. This will also make it easy to add new options in the
future.
2019-02-01 11:34:50 -05:00
Ryuta Kamizono 6127b8d920
Merge pull request #35116 from kamipo/fix_through_association_creation
Fix has_many through association creation
2019-02-01 09:13:43 +09:00
Ryuta Kamizono 0413501691 Remove unused attr_writers `visitor` and `indexes`
I deprecated two unused attr_writers `visitor` and `indexes` at 8056fe0
and f4bc364 conservatively, since those are accidentaly exposed in the
docs.

https://api.rubyonrails.org/v5.2/classes/ActiveRecord/ConnectionAdapters/AbstractAdapter.html
https://api.rubyonrails.org/v5.2/classes/ActiveRecord/ConnectionAdapters/TableDefinition.html

But I've found that `view_renderer` attr_writer is removed without
deprecation at #35093, that is also exposed in the doc.

https://api.rubyonrails.org/v5.2/classes/ActionView/Base.html

I'd like to also remove the deprecated attr_writers since I think that
removing `visitor` and `indexes` attr_writers is as safe as removing
`view_renderer` attr_writer.
2019-02-01 02:32:01 +09:00
Ryuta Kamizono 42d20e8de5 Revert "Merge pull request #33729 from kddeisz/plural-automatic-inverse"
This reverts commit ed1eda271c, reversing
changes made to 3d2caab7dc.

Reason: 7c3da6e003
2019-02-01 01:34:49 +09:00
alkesh26 379354572f ActiveRecord typo fixe. 2019-01-31 16:31:51 +05:30
Abhay Nikam 15db608f3e Fixed typo for DatabaseSelector::Resolver documentation 2019-01-31 07:57:38 +05:30
Ryuta Kamizono 1f5e21bcbc Remove redundant begin block
We enabled `Style/RedundantBegin` cop at #34764, but it is hard to
detect an offence if returning value put after the block.
2019-01-31 10:18:34 +09:00
Olivier Lacan 13f8beb435 Hint at advanced options for foreign_key
We sometimes display simple examples of additional parameters that can be
supplied to table-wise methods like these and I found it particularly difficult
to figure out which options `t.foreign_key` accepts without drilling very deep
into the specific SchemaStatements docs.

Since it's relatively common to create foreign keys with custom column names or
primary keys, it seems like this should help quite a few people.

[ci skip]
2019-01-30 19:29:03 -05:00
John Hawthorn ab952b1949 Write update_last_write_timestamp after request
We need to update using the timestamp from the end of the request, not
the start. For example, if a request spends 5+ seconds writing, we still
want to wait another 5 seconds for replication lag.

Since we now run the update after we yield, we need to use ensure to
make sure we update the timestamp even if there is an exception.
2019-01-30 13:25:09 -08:00
Eileen M. Uchitelle 8ca6bd2e94
Merge pull request #35073 from eileencodes/db-selection
Part 8: Multi db improvements, Adds basic automatic database switching to Rails
2019-01-30 14:03:45 -05:00
Eileen Uchitelle 0abcec416b Adds basic automatic database switching to Rails
The following PR adds behavior to Rails to allow an application to
automatically switch it's connection from the primary to the replica.

A request will be sent to the replica if:

* The request is a read request (`GET` or `HEAD`)
* AND It's been 2 seconds since the last write to the database (because
we don't want to send a user to a replica if the write hasn't made it
to the replica yet)

A request will be sent to the primary if:

* It's not a GET/HEAD request (ie is a POST, PATCH, etc)
* Has been less than 2 seconds since the last write to the database

The implementation that decides when to switch reads (the 2 seconds) is
"safe" to use in production but not recommended without adequate testing
with your infrastructure. At GitHub in addition to the a 5 second delay
we have a curcuit breaker that checks the replication delay
and will send the query to a replica before the 5 seconds has passed.
This is specific to our application and therefore not something Rails
should be doing for you. You'll need to test and implement more robust
handling of when to switch based on your infrastructure. The auto
switcher in Rails is meant to be a basic implementation / API that acts
as a guide for how to implement autoswitching.

The impementation here is meant to be strict enough that you know how to
implement your own resolver and operations classes but flexible enough
that we're not telling you how to do it.

The middleware is not included automatically and can be installed in
your application with the classes you want to use for the resolver and
operations passed in. If you don't pass any classes into the middleware
the Rails default Resolver and Session classes will be used.

The Resolver decides what parameters define when to
switch, Operations sets timestamps for the Resolver to read from. For
example you may want to use cookies instead of a session so you'd
implement a Resolver::Cookies class and pass that into the middleware
via configuration options.

```
config.active_record.database_selector = { delay: 2.seconds }
config.active_record.database_resolver = MyResolver
config.active_record.database_operations = MyResolver::MyCookies
```

Your classes can inherit from the existing classes and reimplment the
methods (or implement more methods) that you need to do the switching.
You only need to implement methods that you want to change. For example
if you wanted to set the session token for the last read from a replica
you would reimplement the `read_from_replica` method in your resolver
class and implement a method that updates a new timestamp in your
operations class.
2019-01-30 13:37:25 -05:00
Eileen Uchitelle dedcc19506 Fix case when we want a UrlConfig but the URL is nil
Previously if the `url` key in a config hash was nil we'd ignore the
configuration as invalid. This can happen when you're relying on a
`DATABASE_URL` in the env and that is not set in the environment.

```
production:
  <<: *default
  url: ENV['DATABASE_URL']
```

This PR fixes that case by checking if there is a `url` key in the
config instead of checking if the `url` is not nil in the config.

In addition to changing the conditional we then need to build a url hash
to merge with the original hash in the `UrlConfig` object.

Fixes #35091
2019-01-30 09:31:35 -05:00
Jean Boussier 74dbce0fca Eagerly materialize the fixtures transaction
The transaction used to restore fixtures is an implementation detail
that should be abstracted away. Idealy a test should behave the same
wether or not transactional fixtures are enabled.

However since transactions have been made lazy, the fixture
transaction started leaking into tests case. e.g. consider the
following (oversimplified) test:

```ruby
class SQLSubscriber
  attr_accessor :sql

  def initialize
    @sql = []
  end

  def call(*, event)
    sql << event[:sql]
  end
end

subscriber = SQLSubscriber.new
ActiveSupport::Notifications.subscribe("sql.active_record", subscriber)

User.connection.execute('SELECT 1', 'Generic name')
assert_equal ['SELECT 1'], subscriber.sql
```

On Rails 6 it starts to break because the `sql` array will be `['BEGIN', 'SELECT 1']`.

Several things are wrong here:

  - That transaction is not generated by the tested code, so it shouldn't be visible.
  - The transaction is not even closed yet, which again doesn't reflect the reality.
2019-01-29 16:10:47 +01:00
Ryuta Kamizono 8309cd2c68
Merge pull request #35071 from kamipo/text_without_limit
MySQL: Support `:size` option to change text and blob size
2019-01-29 17:02:04 +09:00
Aaron Patterson 5bb1ad59b1
Pull `@template` in to a local variable
This gets the PartialRenderer to be a bit closer to the
TemplateRenderer.  TemplateRenderer already keeps its template in a
local variable.
2019-01-28 14:55:12 -08:00
Aaron Patterson e98b51300a
Remove `@view` instance variable from the partial renderer
Similar to 1853b0d0ab
2019-01-28 14:22:32 -08:00
Ryuta Kamizono 1745e905a3 Allow changing text and blob size without giving the `limit` option
In MySQL, the text column size is 65,535 bytes by default (1 GiB in
PostgreSQL). It is sometimes too short when people want to use a text
column, so they sometimes change the text size to mediumtext (16 MiB) or
longtext (4 GiB) by giving the `limit` option.

Unlike MySQL, PostgreSQL doesn't allow the `limit` option for a text
column (raises ERROR: type modifier is not allowed for type "text").
So `limit: 4294967295` (longtext) couldn't be used in Action Text.

I've allowed changing text and blob size without giving the `limit`
option, it prevents that migration failure on PostgreSQL.
2019-01-29 06:49:32 +09:00
Lars Kanis c6d7e70be4 PostgreSQL: Use native timestamp decoders of pg-1.1
This improves performance of timestamp conversion and avoids
additional string allocations.
2019-01-26 20:30:43 +01:00
Ryuta Kamizono 57015cdfa2 Make `t.timestamps` with precision by default 2019-01-26 22:49:14 +09:00
Ryuta Kamizono 5fe6d3747e Fix `t.timestamps` missing `null: false` in `change_table bulk: true` 2019-01-26 21:19:20 +09:00
Ryuta Kamizono 17901d8764 Allow `column_exists?` giving options without type 2019-01-26 21:14:28 +09:00
Eileen M. Uchitelle bf3a8a0e6c
Merge pull request #35042 from eileencodes/fix-error-message-for-missing-handler
Fix error raised when handler doesn't exist
2019-01-25 10:56:00 -05:00
Eileen Uchitelle 1284f826cc Fix error raised when handler doesn't exist
While working on another feature for multiple databases (auto-switching)
I observed that in development the first request won't autoload the
application record connection for the primary database and may not yet
know about the replica connection.

In my test application this caused the application to thrown an error if
I tried to send the first request to the replica before the replica was
connected. This wouldn't be an issue in production because the
application is preloaded.

In order to fix this I decided to leave the original error message and
delete the new error message. I updated the original error message to
include the `role` to make it a bit clearer that the connection isn't
established for that particular role.

The error now reads:

```
No connection pool with 'primary' found for the 'reading' role.
```

A single database application will continue uisng the original error
message:

```
No connection pool with 'primary' found.
```
2019-01-25 09:56:43 -05:00
Kevin Deisz 5cf36e2ea2
Make `And` and `Case` into expression nodes
Allows aliasing, predications, ordering, and various other functions on `And` and `Case` nodes. This brings them in line with other nodes like `Binary` and `Unary`.
2019-01-24 14:35:52 -05:00
Ryuta Kamizono 1fecebae31 Allow `column_exists?` to be passed `type` argument as a string
Currently `conn.column_exists?("testings", "created_at", "datetime")`
returns false even if the table has the `created_at` column.

That reason is that `column.type` is a symbol but passed `type` is not
normalized to symbol unlike `column_name`, it is surprising behavior to
me.

I've improved that to normalize a value before comparison.
2019-01-24 19:02:44 +09:00
Xavier Noria 0065011660 Tell the user what to use instead of update_attributes/! 2019-01-23 22:26:22 +01:00
Dylan Thacker-Smith 5b58cc4f44 activerecord: Fix statement cache for strictly cast attributes 2019-01-23 14:49:42 -05:00
Yasuo Honda 3ea3cccc93 MySQL 8.0.14 adds `ER_FK_INCOMPATIBLE_COLUMNS`
https://dev.mysql.com/doc/relnotes/mysql/8.0/en/news-8-0-14.html
> Error messages relating to creating and dropping foreign keys
> were improved to be more specific and informative. (Bug #28526309, Bug #92087)

https://dev.mysql.com/doc/refman/8.0/en/server-error-reference.html

> Error number: 3780; Symbol: ER_FK_INCOMPATIBLE_COLUMNS; SQLSTATE: HY000
> Message: Referencing column '%s' and referenced column '%s' in foreign key constraint '%s' are incompatible.
> ER_FK_INCOMPATIBLE_COLUMNS was added in 8.0.14.
2019-01-22 15:15:52 +00:00
Kevin Deisz 65cec345b4
Alias case nodes
When `Arel` was merged into `ActiveRecord` we lost the ability to alias case nodes. This adds it back.
2019-01-21 10:28:39 -05:00
Ryuta Kamizono 4a0e3809be Fix type casting column default in `change_column`
Since #31230, `change_column` is executed as a bulk statement.

That caused incorrect type casting column default by looking up the
before changed type, not the after changed type.

In a bulk statement, we can't use `change_column_default_for_alter` if
the statement changes the column type.

This fixes the type casting to use the constructed target sql_type.

Fixes #34938.
2019-01-20 11:09:00 +09:00
Rafael Mendonça França 5a0230c67f
Preparing for 6.0.0.beta1 release 2019-01-18 15:42:12 -05:00
Dylan Thacker-Smith 592a961f29 activerecord: Fix where nil condition on composed_of attribute 2019-01-18 11:10:10 -05:00
Ryuta Kamizono ff3d1a42d5
Merge pull request #30000 from kamipo/all_of_queries_should_return_correct_result
All of queries should return correct result even if including large number
2019-01-18 22:58:54 +09:00
Eileen M. Uchitelle 7235e84935
Merge pull request #34969 from eileencodes/fix-error-message-for-multi-db-apps
Fix error message when adapter is not specified
2019-01-18 07:53:26 -05:00
Ryuta Kamizono c196ca72a0 Ensure `StatementCache#execute` never raises `RangeError`
Since 31ffbf8d, finder methods no longer raise `RangeError`. So
`StatementCache#execute` is the only place to raise the exception for
finder queries.

`StatementCache` is used for simple equality queries in the codebase.
This means that if `StatementCache#execute` raises `RangeError`, the
result could always be regarded as empty.
So `StatementCache#execute` just return nil in that range error case,
and treat that as empty in the caller side, then we can avoid catching
the exception in much places.
2019-01-18 16:01:14 +09:00
Ryuta Kamizono 31ffbf8d50 All of queries should return correct result even if including large number
Currently several queries cannot return correct result due to incorrect
`RangeError` handling.

First example:

```ruby
assert_equal true, Topic.where(id: [1, 9223372036854775808]).exists?
assert_equal true, Topic.where.not(id: 9223372036854775808).exists?
```

The first example is obviously to be true, but currently it returns
false.

Second example:

```ruby
assert_equal topics(:first), Topic.where(id: 1..9223372036854775808).find(1)
```

The second example also should return the object, but currently it
raises `RecordNotFound`.

It can be seen from the examples, the queries including large number
assuming empty result is not always correct.

Therefore, This change handles `RangeError` to generate executable SQL
instead of raising `RangeError` to users to always return correct
result. By this change, it is no longer raised `RangeError` to users.
2019-01-18 16:01:07 +09:00
Ryuta Kamizono 5b6daff5b6 Use `unboundable?` rather than `boundable?`
The `unboundable?` behaves like the `infinite?`.

```ruby
inf = Topic.predicate_builder.build_bind_attribute(:id, Float::INFINITY)
inf.infinite?    # => 1

oob = Topic.predicate_builder.build_bind_attribute(:id, 9999999999999999999999999999999)
oob.unboundable? # => 1

inf = Topic.predicate_builder.build_bind_attribute(:id, -Float::INFINITY)
inf.infinite?    # => -1

oob = Topic.predicate_builder.build_bind_attribute(:id, -9999999999999999999999999999999)
oob.unboundable? # => -1
```
2019-01-18 14:56:43 +09:00
Rafael França 41dc4d9490
Merge pull request #34963 from dylanahsmith/better-composed-of-single-field-query
activerecord: Use a simpler query condition for aggregates with one mapping
2019-01-17 18:32:27 -05:00
Eileen Uchitelle 83b995206a Fix error message when adapter is not specified
When we added support for multiple databases through a 3-tiered config
and configuration objects this error message got a bit convoluted.

Previously if you had an application with a missing configuation and
multiple databases the error message would look like this:

```
'doesnexist' database is not configured. Available: development,
development, test, test, production, production
(ActiveRecord::AdapterNotSpecified)
```

That's not very descriptive since it duplicates the environments
(because there are multiple databases per environment for this
application).

To fix this I've constructed a bit more readable error message which now
reads like this if you have a multi db app:

```
The `doesntexist` database is not configured for the `production`
environment. (ActiveRecord::AdapterNotSpecified)

Available databases configurations are:

development: primary, primary_readonly
test: primary, primary_readonly
production: primary, primary_readonly
```

And like this if you have a single db app:

```
The `doesntexist` database is not configured for the `production`
environment. (ActiveRecord::AdapterNotSpecified)

Available databases configurations are:

development
test
```

This makes the error message more readable and presents the user all
available options for the database connections.
2019-01-17 17:26:32 -05:00
Ryuta Kamizono 9905cdc946
Use public_send instead since respond_to? doesn't include private/protected methods by default
Co-Authored-By: dylanahsmith <dylan.smith@shopify.com>
2019-01-17 17:00:10 -05:00
Rafael Mendonça França 6c745b0c51
Remove deprecated `#set_state` from the transaction object 2019-01-17 16:08:33 -05:00
Rafael Mendonça França 5f3ed87843
Remove deprecated `#supports_statement_cache?` from the database adapters 2019-01-17 16:08:33 -05:00
Rafael Mendonça França 400ba786e1
Remove deprecated `#insert_fixtures` from the database adapters 2019-01-17 16:08:33 -05:00
Rafael Mendonça França 45b4d5f81f
Remove deprecated `ActiveRecord::ConnectionAdapters::SQLite3Adapter#valid_alter_table_type?` 2019-01-17 16:08:33 -05:00
Rafael Mendonça França 91ddb30083
Do not allow passing the column name to `sum` when a block is passed 2019-01-17 16:08:33 -05:00
Rafael Mendonça França 67356f2034
Do not allow passing the column name to `count` when a block is passed 2019-01-17 16:08:33 -05:00
Rafael Mendonça França d97980a16d
Remove delegation of missing methods in a relation to arel 2019-01-17 16:08:32 -05:00
Rafael Mendonça França a7becf147a
Remove delegation of missing methods in a relation to private methods of the class 2019-01-17 16:08:32 -05:00
Rafael Mendonça França f59b08119b
Change `SQLite3Adapter` to always represent boolean values as integers 2019-01-17 16:08:32 -05:00
Rafael Mendonça França 0bef23e630
Remove ability to specify a timestamp name for `#cache_key` 2019-01-17 16:08:32 -05:00
Rafael Mendonça França 90d7842186
Remove deprecated `ActiveRecord::Migrator.migrations_path=` 2019-01-17 16:08:32 -05:00
Rafael Mendonça França 27b252d6a8
Remove deprecated `expand_hash_conditions_for_aggregates` 2019-01-17 16:08:32 -05:00
Dylan Thacker-Smith b278db1d23 Avoid using yield_self to make it easier to backport 2019-01-17 14:16:13 -05:00
Dylan Thacker-Smith 242fc54f57 activerecord: Use a simpler query condition for aggregates with one mapping 2019-01-17 13:37:11 -05:00
bogdanvlviv 2bad3f46cd
Add foreign key to active_storage_attachments for `blob_id` via new migration
We need this in order to be able to add this migration for users that
use ActiveStorage during update their apps from Rails 5.2 to Rails 6.0.

Related to #33405

`rake app:update` should update active_storage

`rake app:update` should execute `rake active_storage:update`
if it is used in the app that is being updated.
It will add new active_storage's migrations to users' apps during update Rails.

Context https://github.com/rails/rails/pull/33405#discussion_r204239399

Also, see a related discussion in the Campfire:
https://3.basecamp.com/3076981/buckets/24956/chats/12416418@1236713081
2019-01-16 13:13:23 +00:00
Laerti 41ffddbc8b Refs #28025 nullify *_type column on polymorphic associations on :nu… (#28078)
This PR addresses the issue described in #28025. On `dependent: :nullify` strategy only the foreign key of the relation is nullified. However on polymorphic associations the  `*_type` column is not nullified leaving the record with a NULL `*_id` but the `*_type` column is present.
2019-01-15 23:03:20 +09:00
Ryuta Kamizono e4213e7c68 Remove public `prevent_writes` writer
The `@prevent_writes` should be updated only in the
`while_preventing_writes`, it is not necessary to expose the attr
writer.
2019-01-15 22:55:31 +09:00
Ryuta Kamizono 8056fe0d96 Deprecate `connection.visitor = ...` which is not released internal usage
This attr writer was introduced at 7db90aa, but the usage is already
removed at bd2f5c0 before v3.2.0.rc1 is released.

If we'd like to customize the visitor in the connection, `arel_visitor`
which is implemented in all adapters (mysql2, postgresql, sqlite3,
oracle-enhanced, sqlserver) could be used for the purpose #23515.
2019-01-15 22:44:27 +09:00
Ryuta Kamizono 862c78b26f Remove unused `Arel::Compatibility::Wheres`
This class is no longer used since 9cbfc8a370.
2019-01-15 22:13:25 +09:00
Rafael França fcd38cf19f
Merge pull request #34891 from gmcgibbon/ac_params_exists
Allow strong params in ActiveRecord::Base#exists?
2019-01-14 17:34:44 -05:00
Ryuta Kamizono bb75d68fe2 More exercise test cases for `not_between`
And support endless ranges for `not_between` like as `between`.

Follow up #34906.
2019-01-12 07:44:27 +09:00
Aaron Patterson 74bef0970f
Merge branch 'master' into ac_params_exists 2019-01-11 11:21:53 -08:00
Aaron Patterson 3a1b2a2196
Merge pull request #34906 from gregnavis/add-endless-ranges-to-activerecord
Support endless ranges in where
2019-01-11 11:20:05 -08:00
Greg Navis 7110dbea00 Support endless ranges in where
This commit adds support for endless ranges, e.g. (1..), that were added
in Ruby 2.6. They're functionally equivalent to explicitly specifying
Float::INFINITY as the end of the range.
2019-01-11 14:27:34 +01:00
Ryuta Kamizono 5f9e0f848e Remove `id_value` argument which is no longer passed to `sql_for_insert`
Since #26002, `id_value` is no longer passed to `sql_for_insert`.
2019-01-11 19:55:14 +09:00
Ryuta Kamizono 6c6c32463e Refactor `bind_attribute` to expand an association to actual attribute 2019-01-11 18:01:55 +09:00
Ryuta Kamizono eb5fef554f Refactor `build_relation` in the uniqueness validator to avoid low level predicate construction 2019-01-11 17:32:48 +09:00
Ryuta Kamizono ea65d92f19
Enable `Lint/UselessAssignment` cop to avoid unused variable warnings (#34904)
* Enable `Lint/UselessAssignment` cop to avoid unused variable warnings

Since we've addressed the warning "assigned but unused variable"
frequently.

370537de05
3040446cec
5ed618e192
76ebafe594

And also, I've found the unused args in c1b14ad which raises no warnings
by the cop, it shows the value of the cop.
2019-01-09 18:09:01 +09:00
Ryuta Kamizono 7f856c3c8d Consolidate the duplicated code that building range predicate
This slightly change the code in the Arel to allow +/-INFINITY as open
ended since the Active Record expects that behavior. See 5ecbeda.
2019-01-08 16:45:17 +09:00
bannzai 45cfe9f8b6 ♻️ Fix mysql type map for enum and set 2019-01-08 14:56:46 +09:00
Gannon McGibbon 1e923b4984 Allow strong params in ActiveRecord::Base#exists?
Allow `ActionController::Params` as argument of
`ActiveRecord::Base#exists?`
2019-01-07 14:59:02 -05:00
Eileen M. Uchitelle 725c6422e7
Merge pull request #34773 from eileencodes/share-fixture-connections-with-multiple-handlers
For fixtures share the connection pool when there are multiple handlers
2019-01-04 08:49:17 -05:00
Ryuta Kamizono a5a22c4ea1
Merge pull request #34858 from albertoalmagro/make-rails-compatible-accross-ruby-versions
Make average compatible across ruby versions
2019-01-04 10:32:37 +09:00
Alberto Almagro d237c7c72c Make average compatible accross Ruby versions
Since Ruby 2.6.0 NilClass#to_d is returning `BigDecimal` 0.0, this
breaks `average` compatibility with prior Ruby versions. This patch
makes `average` return `nil` in all Ruby versions when there are no
rows.
2019-01-04 00:41:22 +01:00
Ryuta Kamizono 7a4e20e0cd Merge the redundant `when Symbol` case to the `when String, ...` 2019-01-04 08:05:17 +09:00
Ryuta Kamizono e9aa0c5c72 2x faster `connection.type_cast`
`nil`, `Numeric`, and `String` are most basic objects which are passed
to `type_cast`. But now each `when *types_which_need_no_typecasting`
evaluation allocates extra two arrays, it makes `type_cast` slower.

The `types_which_need_no_typecasting` was introduced at #15351, but the
method isn't useful (never used any adapters) since all adapters
(sqlite3, mysql2, postgresql, oracle-enhanced, sqlserver) still
overrides the `_type_cast`.

Just expanding the method would make the `type_cast` 2x faster.

```ruby
module ActiveRecord
  module TypeCastFast
    def type_cast_fast(value, column = nil)
      value = id_value_for_database(value) if value.is_a?(Base)

      if column
        value = type_cast_from_column(column, value)
      end

      _type_cast_fast(value)
    rescue TypeError
      to_type = column ? " to #{column.type}" : ""
      raise TypeError, "can't cast #{value.class}#{to_type}"
    end

    private
      def _type_cast_fast(value)
        case value
        when Symbol, ActiveSupport::Multibyte::Chars, Type::Binary::Data
          value.to_s
        when true       then unquoted_true
        when false      then unquoted_false
        # BigDecimals need to be put in a non-normalized form and quoted.
        when BigDecimal then value.to_s("F")
        when nil, Numeric, String then value
        when Type::Time::Value then quoted_time(value)
        when Date, Time then quoted_date(value)
        else raise TypeError
        end
      end
  end
end

conn = ActiveRecord::Base.connection
conn.extend ActiveRecord::TypeCastFast

Benchmark.ips do |x|
  x.report("type_cast") { conn.type_cast("foo") }
  x.report("type_cast_fast") { conn.type_cast_fast("foo") }
  x.compare!
end
```

```
Warming up --------------------------------------
           type_cast    58.733k i/100ms
      type_cast_fast   101.364k i/100ms
Calculating -------------------------------------
           type_cast    708.066k (± 5.9%) i/s -      3.583M in   5.080866s
      type_cast_fast      1.424M (± 2.3%) i/s -      7.197M in   5.055860s

Comparison:
      type_cast_fast:  1424240.0 i/s
           type_cast:   708066.0 i/s - 2.01x  slower
```
2019-01-04 07:24:57 +09:00
Eileen Uchitelle b24bfcce77 Share the connection pool when there are multiple handlers
In an application that has a primary and replica database the data
inserted on the primary connection will not be able to be read by the
replica connection.

In a test like this:

```
test "creating a home and then reading it" do
  home = Home.create!(owner: "eileencodes")

  ActiveRecord::Base.connected_to(role: :default) do
    assert_equal 3, Home.count
  end

  ActiveRecord::Base.connected_to(role: :readonly) do
    assert_equal 3, Home.count
  end
end
```

The home inserted in the beginning of the test can't be read by the
replica database because when the test is started a transasction is
opened byy `setup_fixtures`. That transaction remains open for the
remainder of the test until we are done and run `teardown_fixtures`.

Because the data isn't actually committed to the database the replica
database cannot see the data insertion.

I considered a couple ways to fix this. I could have written a database
cleaner like class that would allow the data to be committed and then
clean up that data afterwards. But database cleaners can make the
database slow and the point of the fixtures is to be fast.

In GitHub we solve this by sharing the connection pool for the replicas
with the primary (writing) connection. This is a bit hacky but it works.
Additionally since we define `replica? || preventing_writes?` as the
code that blocks writes to the database this will still prevent writing
on the replica / readonly connection. So we get all the behavior of
multiple connections for the same database without slowing down the
database.

In this PR the code loops through the handlers. If the handler doesn't
match the default handler then it retrieves the connection pool from the
default / writing handler and assigns the reading handler's connections
to that pool.

Then in enlist_fixture_connections it maps all the connections for the
default handler because all the connections are now available on that
handler so we don't need to loop through them again.

The test uses a temporary connection pool so we can test this with
sqlite3_mem. This adapter doesn't behave the same as the others and
after looking over how the query cache test works I think this is the
most correct. The issues comes when calling `connects_to` because that
establishes new connections and confuses the sqlite3_mem adapter. I'm
not entirely sure why but I wanted to make sure we tested all adapters
for this change and I checked that it wasn't the shared connection code
that was causing issues - it was the `connects_to` code.
2019-01-03 16:32:46 -05:00
Kasper Timm Hansen 6f0cda8f8e
Merge pull request #33985 from eugeneius/attribute_methods_schema_cache
Only define attribute methods from schema cache
2019-01-03 15:03:06 +01:00
Ryuta Kamizono 260b273106
Merge pull request #34836 from kamipo/class_level_update_without_ids
Restore an ability that class level `update` without giving ids
2019-01-02 23:42:16 +09:00
Ryuta Kamizono fb6743acc5 MariaDB: Remove version checking lower the 5.5.8
Since we already bumped the minimum version of MySQL to 5.5.8 at #33853.
2019-01-02 10:50:21 +09:00
Ryuta Kamizono 3d5db4920a Add test case for `preventing_writes?`
Since the `preventing_writes?` is public API.
2019-01-02 08:42:50 +09:00
yuuji.yaginuma 2484443aa8 Bring ActiveRecord::Core's API document back [ci skip]
If exist `:nodoc:` before method define, it affects all subsequent
method definitions.
2019-01-02 08:32:17 +09:00
Ryuta Kamizono 4c05434973 Restore an ability that class level `update` without giving ids
That ability was introduced at #11898 as `Relation#update` without
giving ids, so the ability on the class level is not documented and not
tested.

c83e30d which fixes #33470 has lost two undocumented abilities.

One has fixed at 5c65688, but I missed the ability on the class level.

Removing any feature should not be suddenly happened in a stable version
even if that is not documented.

I've restored the ability and added test case to avoid any regression in
the future.

Fixes #34743.
2019-01-02 06:23:52 +09:00
Ryuta Kamizono 600a66f60c Fix TypeError: no implicit conversion of Arel::Attributes::Attribute into String properly
This reverts 27c6c07 since `arel_attr.to_s` is not right way to avoid
the type error.

That to_s returns `"#<struct Arel::Attributes::Attribute ...>"`, there
is no reason to match the regex to the inspect form.

And also, the regex path is not covered by our test cases. I've tweaked
the regex for redundant part and added assertions for the regex path.
2019-01-02 04:15:32 +09:00
Arun Agrawal 50e3680768 Bump license years for 2019 2018-12-31 10:24:38 +07:00
Ryuta Kamizono 22a6ff68b1 Use high level API on `migration_context` instead of using low level API directly
Since `migration_context` has `migrations_paths` itself and provides
methods which returning values from parsed migration files, so there is
no reason to use the `parse_migration_filename` low level API directly.
2018-12-28 10:17:12 +09:00
Ryuta Kamizono c1b14aded2 Deprecate passing `migrations_paths` to `connection.assume_migrated_upto_version`
Since #31727, `migrations_paths` in `assume_migrated_upto_version` is no
longer used.
2018-12-28 09:21:09 +09:00
Ryuta Kamizono 4ae8d6182f Merge pull request #34806 from bogdan/reuse-find-target
Reuse AR::Association#find_target method
2018-12-27 19:40:10 +09:00
Bogdan Gusiev bc30d421f3 Reuse AR::Association#find_target method 2018-12-27 11:53:27 +02:00
Eileen M. Uchitelle b00e46bd6d
Merge pull request #34753 from eileencodes/raise-less-confusing-error-if-handler-doesnt-exist
Raise helpful error when role doesn't exist
2018-12-21 11:43:35 -05:00
Eileen Uchitelle 22a1265828 Raise helpful error when role doesn't exist
If you try to call `connected_to` with a role that doesn't have an
established connection you used to get an error that said:

```
>> ActiveRecord::Base.connected_to(role: :i_dont_exist) { Home.first }

ActiveRecord::ConnectionNotEstablished Exception: No connection pool
with 'primary' found.
```

This is confusing because the connection could be established but we
spelled the role wrong.

I've changed this to raise if the `role` used in `connected_to` doesn't
have an associated handler. Users who encounter this should either check
that the role is spelled correctly (writin -> writing), establish a
connection to that role in the model with connects_to, or use the
`database` keyword for the `role`.

I think this will provide a less confusing error message for those
starting out with multiple databases.
2018-12-21 11:10:10 -05:00
Ryuta Kamizono 721e26767c
Merge pull request #34742 from kamipo/row_format_dynamic_by_default
MySQL: `ROW_FORMAT=DYNAMIC` create table option by default
2018-12-21 17:39:31 +09:00
Ryuta Kamizono 892e38c78e Enable `Style/RedundantBegin` cop to avoid newly adding redundant begin block
Currently we sometimes find a redundant begin block in code review
(e.g. https://github.com/rails/rails/pull/33604#discussion_r209784205).

I'd like to enable `Style/RedundantBegin` cop to avoid that, since
rescue/else/ensure are allowed inside do/end blocks in Ruby 2.5
(https://bugs.ruby-lang.org/issues/12906), so we'd probably meets with
that situation than before.
2018-12-21 06:12:42 +09:00
Ryuta Kamizono 8034dde023 Module#{define_method,alias_method,undef_method,remove_method} become public since Ruby 2.5
https://bugs.ruby-lang.org/issues/14133
2018-12-21 01:39:18 +09:00
Ryuta Kamizono 3e50a1bcd4
Merge pull request #30973 from k0kubun/prefer-block-parameter
Unify _read_attribute definition to use &block
2018-12-20 17:38:32 +09:00
Takashi Kokubun f3c866a743 Unify _read_attribute definition to use &block
Thanks to ko1, passing block parameter to another method is
significantly optimized in Ruby 2.5.
https://bugs.ruby-lang.org/issues/14045

Thus we no longer need to keep this ugly hack.
2018-12-20 10:37:15 +09:00
Ryuta Kamizono a1652c196e MySQL: `ROW_FORMAT=DYNAMIC` create table option by default
Since MySQL 5.7.9, the `innodb_default_row_format` option defines the
default row format for InnoDB tables. The default setting is `DYNAMIC`.

The row format is required for indexing on `varchar(255)` with `utf8mb4`
columns.

As long as using MySQL 5.6, CI won't be passed even if MySQL server
setting is properly configured the same as MySQL 5.7
(`innodb_file_per_table = 1`, `innodb_file_format = 'Barracuda'`, and
`innodb_large_prefix = 1`) since InnoDB table is created as the row
format `COMPACT` by default on MySQL 5.6, therefore indexing on string
with `utf8mb4` columns aren't succeeded.

Making `ROW_FORMAT=DYNAMIC` create table option by default for legacy
MySQL version would mitigate the indexing issue on the user side, and it
makes CI would be passed on MySQL 5.6 which is configured properly.
2018-12-19 08:53:16 +09:00
Ryuta Kamizono 0fa5b5510c Use `utf8mb4` charset for internal tables if the row format `DYNAMIC` by default
The indexing issue on `utf8mb4` columns is resolved since MySQL 5.7.9.
2018-12-19 08:38:12 +09:00
Ryuta Kamizono 7d83ef4f7b Ensure that preventing writes is invoked before `materialize_transactions` consistently 2018-12-12 23:14:26 +09:00
John Hawthorn b67a3f5cac Add AR::Base.connected_to?
This can be used to check the currently connected role. It's meant to
mirror AR::Base.connected_to
2018-12-11 14:24:02 -08:00
Ryuta Kamizono 5742344024 An empty transaction does not raise the `ReadOnlyError` if preventing writes
BEGIN transaction would cause COMMIT or ROLLBACK, so unless COMMIT and
ROLLBACK aren't treated as write queries as well as BEGIN, the
`ReadOnlyError` would be raised.
2018-12-11 21:07:37 +09:00
Rafael França b310827506
Merge pull request #34666 from vinistock/upgrade_rubocop_and_fix_offenses
Upgrade Rubocop to 0.61.1 and fix offenses
2018-12-10 17:38:47 -05:00
Ryuta Kamizono 10457475b9 An explain query does not raise the `ReadOnlyError` if preventing writes 2018-12-11 07:23:00 +09:00
Ryuta Kamizono 07f0f1a8c7 Don't treat begin and rollback transactions as write queries
Otherwise `save` method would raise the `ReadOnlyError` against `BEGIN`
and `ROLLBACK` queries.
2018-12-11 06:40:38 +09:00
Vinicius Stock 3b7a4d3d75
Upgrade Rubocop to 0.61.1 and fix offenses 2018-12-10 19:22:56 -02:00
Ryuta Kamizono cf71f31e2e Prevent write queries with prepared statements for mysql2 adapter
Without this change, mysql2 adapter with prepared statements won't pass
`base_test.rb`.

```
% ARCONN=mysql2 be ruby -w -Itest test/cases/base_test.rb
Using mysql2
Run options: --seed 27614

# Running:

....S..............................F

Failure:
BasicsTest#test_creating_a_record_raises_if_preventing_writes [test/cases/base_test.rb:1493]:
ActiveRecord::ReadOnlyError expected but nothing was raised.

rails test test/cases/base_test.rb:1492

...F

Failure:
BasicsTest#test_deleting_a_record_raises_if_preventing_writes [test/cases/base_test.rb:1513]:
ActiveRecord::ReadOnlyError expected but nothing was raised.

rails test test/cases/base_test.rb:1510

............................................................................................................F

Failure:
BasicsTest#test_updating_a_record_raises_if_preventing_writes [test/cases/base_test.rb:1503]:
ActiveRecord::ReadOnlyError expected but nothing was raised.

rails test test/cases/base_test.rb:1500

..........

Finished in 2.534490s, 62.7345 runs/s, 149.5370 assertions/s.
159 runs, 379 assertions, 3 failures, 0 errors, 1 skips
```
2018-12-11 05:08:59 +09:00
Ryuta Kamizono bde898c1df Prevent write queries for `exec_query`
Follow up #34505.
2018-12-11 04:51:54 +09:00
Eileen M. Uchitelle bdc96802a7
Merge pull request #34632 from rails/rename-write-on-read-error
Rename error that occurs when writing on a read
2018-12-07 17:54:33 -05:00
Bogdan 18f83faf71 #create_or_find_by/!: add more tests and fix docs (#34653)
* `#create_or_find_by/!`: add more tests

* Fix docs of `create_or_find_by`

This method uses `find_by!` internally.
2018-12-08 07:46:30 +09:00
Eileen Uchitelle db54afba2e Rename error that occurs when writing on a read
I originally named this `StatementInvalid` because that's what we do in
GitHub, but `@tenderlove` pointed out that this means apps can't test
for or explitly rescue this error. `StatementInvalid` is pretty broad so
I've renamed this to `ReadOnlyError`.
2018-12-07 08:53:47 -05:00
Gannon McGibbon 93f19071ad Fix join table column quoting with SQLite. 2018-12-05 11:56:14 -05:00
Alfred Dominic c4d157aafe option to disable scopes that `ActiveRecord.enum` generates by default 2018-12-04 15:56:31 +05:30
Ryuta Kamizono 609c58bfa6 Merge pull request #34609 from kamipo/delete_all_on_collection_proxy
Ensure that `delete_all` on collection proxy returns affected count
2018-12-04 15:48:22 +09:00
Ryuta Kamizono 4d7354aa35 Ensure that `delete_all` on collection proxy returns affected count
Unlike the `Relation#delete_all`, `delete_all` on collection proxy
doesn't return affected count. Since the `CollectionProxy` is a subclass
of the `Relation`, this inconsistency is probably not intended, so it
should return the count consistently.
2018-12-04 14:33:31 +09:00
Gannon McGibbon 67bca35a64 Reset scope after collection delete
Reset scope after delete on collection association to clear stale
offsets of removed records.
2018-12-04 00:16:42 -05:00
Rafael França e167818687
Merge pull request #34602 from guizmaii/master
Pass the `connection` to the `@instrumenter.instrument` method call
2018-12-03 10:47:50 -05:00
Ryuta Kamizono df76eaa4f1 Address "warning: shadowing outer local variable - parts"
And hide the `READ_QUERY` internal constant.
2018-12-03 19:57:27 +09:00
jules Ivanic 6d1c9a9b23 Pass the `connection` to the `@instrumenter.instrument` method call 2018-12-03 10:12:14 +01:00
Gannon McGibbon 220494185c Clarify no support for non PK id columns
[ci skip]
2018-11-30 13:25:42 -05:00
Eileen Uchitelle f39d72d526 Add ability to prevent writes to a database
This PR adds the ability to prevent writes to a database even if the
database user is able to write (ie the database is a primary and not a
replica).

This is useful for a few reasons: 1) when converting your database from
a single db to a primary/replica setup - you can fix all the writes on
reads early on, 2) when we implement automatic database switching or
when an app is manually switching connections this feature can be used
to ensure reads are reading and writes are writing. We want to make sure
we raise if we ever try to write in read mode, regardless of database
type and 3) for local development if you don't want to set up multiple
databases but do want to support rw/ro queries.

This should be used in conjunction with `connected_to` in write mode.
For example:

```
ActiveRecord::Base.connected_to(role: :writing) do
  Dog.connection.while_preventing_writes do
    Dog.create! # will raise because we're preventing writes
  end
end

ActiveRecord::Base.connected_to(role: :reading) do
  Dog.connection.while_preventing_writes do
    Dog.first # will not raise because we're not writing
  end
end
```
2018-11-30 09:28:04 -05:00
Ryuta Kamizono 5c6316dbb8
Merge pull request #34572 from kamipo/fix_scoping_with_query_method
Fix the scoping with query methods in the scope block
2018-11-30 21:41:12 +09:00
Ryuta Kamizono faf91b0db4 Use the full link URL instead of bit.ly [ci skip] 2018-11-30 21:37:28 +09:00
Ryuta Kamizono 3090b35848 Fix the scoping with query methods in the scope block
Follow up #33394.

#33394 only fixes the case of scoping with klass methods in the scope
block which invokes `klass.all`.
Query methods in the scope block also need to invoke `klass.all` to be
affected by the scoping.
2018-11-30 05:50:40 +09:00
Gannon McGibbon 72e63c71bb Allow aliased attributes in update
Allow aliased attributes to be used in `#update_columns` and `#update`.
2018-11-29 14:49:17 -05:00
Rafael França 89595aff8e
Merge pull request #34562 from ruralocity/active-record-query-docs-improvement
Improve ActiveRecord::Querying documentation [ci skip]
2018-11-28 18:07:24 -05:00
Aaron Sumner 96f6a59d8e Improve ActiveRecord::Querying documentation [ci skip]
* Break up long sentences
* Reword some sentences to clarify subject, predicate, and object
* Explain drawbacks of using count_by_sql
2018-11-28 14:50:25 -08:00
Gannon McGibbon 03fadebe0e Allow spaces in postgres table names
Fixes issue where "user post" is misinterpreted as "\"user\".\"post\""
when quoting table names with the postgres adapter.
2018-11-28 16:20:22 -05:00
Rafael França 9c6e362a63
Merge pull request #34557 from sergioisidoro/sergio-patch-load-error
Patch load error in case GemSpecError
2018-11-28 12:51:39 -05:00
sergioisidoro a1a08ac7ca
Patch load error in case GemSpecError 2018-11-28 16:57:32 +02:00
Sean Griffin 9c4d3c341c
Merge pull request #33835 from schneems/schneems/faster_cache_version
Use raw time string from DB to generate ActiveRecord#cache_version
2018-11-27 18:51:20 -07:00
Rafael França ddaca7ccec
Merge pull request #34528 from DmitryTsepelev/fix-ignored-attributes
Additional types of ResultSet should not contain keys of #attributes_to_define_after_schema_loads
2018-11-27 14:43:01 -05:00
Ryuta Kamizono 93c94973ab Revert "Merge pull request #34538 from bogdan/reuse-find-target"
This reverts commit f2ab8b64d4, reversing
changes made to b9c7305dbe.

Reason: `scope.take` is not the same with `scope.to_a.first`.
2018-11-28 01:09:35 +09:00
Eileen M. Uchitelle f2ab8b64d4
Merge pull request #34538 from bogdan/reuse-find-target
Reuse code in AR::Association#find_target
2018-11-27 10:58:10 -05:00
DmitryTsepelev d34c1fc3d6 Cached columns_hash fields should be excluded from ResultSet#column_types 2018-11-27 16:30:26 +03:00
Eileen M. Uchitelle b9c7305dbe
Merge pull request #34480 from tekin/configurable-implicit-ordering-column
Make it possible to override the implicit order column
2018-11-27 08:19:50 -05:00
Bogdan Gusiev 68acbe8a3a Reuse code in AR::Association#find_target
Before this patch, singular and collection associations
had different implementations of the #find_target method.
This patch reuses the code properly through extending the low level
methods.
2018-11-27 12:05:02 +02:00
Ryuta Kamizono b566be2349 Revert "We still need the `Helpers` constant in the `ActiveRecord` namespace"
This reverts commit d52f74480a.

Since 24adc20, the `Helpers` constant in the `ActiveRecord` namespace is
not referenced anymore.
2018-11-27 15:25:36 +09:00
Ryuta Kamizono 24adc20ace `Mutable` helper is in `ActiveModel`
It should be referenced by full qualified name from Active Record.
2018-11-27 15:02:44 +09:00
Tekin Suleyman 3b9982a3b7
Make implicit order column configurable
When calling ordered finder methods such as +first+ or +last+ without an
explicit order clause, ActiveRecord sorts records by primary key. This
can result in unpredictable and surprising behaviour when the primary
key is not an auto-incrementing integer, for example when it's a UUID.
This change makes it possible to override the column used for implicit
ordering such that +first+ and +last+ will return more predictable
results. For Example:

  class Project < ActiveRecord::Base
    self.implicit_order_column = "created_at"
  end
2018-11-26 16:19:52 -08:00
Rafael França 713e75d46d
Merge pull request #34520 from yahonda/bump_pg93
Bump the minimum version of PostgreSQL to 9.3
2018-11-26 11:59:05 -05:00
Alireza Bashiri c0d7a27d9d When running exec_query MySQL always returns ActiveRecord::Result
When running `exec_query` with `INSERT` (or other write commands), MySQL
returns `ActiveRecord::Result`.
2018-11-25 22:10:18 +07:00
Yasuo Honda 6fb128d144 Bump the minimum version of PostgreSQL to 9.3
https://www.postgresql.org/support/versioning/

- 9.1 EOLed on September 2016.
- 9.2 EOLed on September 2017.

9.3 is also not supported since Nov 8, 2018.  https://www.postgresql.org/about/news/1905/
I think it may be a little bit early to drop PostgreSQL 9.3 yet.

* Deprecated `supports_ranges?` since no other databases support range data type

* Add `supports_materialized_views?` to abstract adapter
Materialized views itself is supported by other databases, other connection adapters may support them

* Remove `with_manual_interventions`
It was only necessary for PostgreSQL 9.1 or earlier

* Drop CI against PostgreSQL 9.2
2018-11-25 13:13:08 +00:00
ebyrds 4c8c31774a Raises error when attempting to modify enum values 2018-11-23 23:55:31 +00:00
Rafael França 246ee77eef
Merge pull request #34468 from gmcgibbon/redact_sql_in_errors
Redact SQL in errors
2018-11-23 16:45:23 -05:00
Gannon McGibbon 192b7bcfac Redact SQL in errors
Move `ActiveRecord::StatementInvalid` SQL to error property.
Also add bindings as an error property.
2018-11-22 13:53:23 -05:00
Ryuta Kamizono 1b68ead8f8 Use squiggly heredoc to strip odd indentation in the executed SQL
Before:

```
LOG:  execute <unnamed>:             SELECT t.oid, t.typname
                    FROM pg_type as t
                    WHERE t.typname IN ('int2', 'int4', 'int8', 'oid', 'float4', 'float8', 'bool')

LOG:  execute <unnamed>:               SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, r.rngsubtype, t.typtype, t.typbasetype
                      FROM pg_type as t
                      LEFT JOIN pg_range as r ON oid = rngtypid
                      WHERE
                        t.typname IN ('int2', 'int4', 'int8', 'oid', 'float4', 'float8', 'text', 'varchar', 'char', 'name', 'bpchar', 'bool', 'bit', 'varbit', 'timestamptz', 'date', 'money', 'bytea', 'point', 'hstore', 'json', 'jsonb', 'cidr', 'inet', 'uuid', 'xml', 'tsvector', 'macaddr', 'citext', 'ltree', 'interval', 'path', 'line', 'polygon', 'circle', 'lseg', 'box', 'time', 'timestamp', 'numeric')
                        OR t.typtype IN ('r', 'e', 'd')
                        OR t.typinput::varchar = 'array_in'
                        OR t.typelem != 0

LOG:  statement: SHOW TIME ZONE
LOG:  statement: SELECT 1
LOG:  execute <unnamed>:               SELECT COUNT(*)
                      FROM pg_class c
                      LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
                      WHERE c.relkind IN ('r','v','m') -- (r)elation/table, (v)iew, (m)aterialized view
                      AND c.relname = 'accounts'
                      AND n.nspname = ANY (current_schemas(false))
```

After:

```
LOG:  execute <unnamed>: SELECT t.oid, t.typname
        FROM pg_type as t
        WHERE t.typname IN ('int2', 'int4', 'int8', 'oid', 'float4', 'float8', 'bool')

LOG:  execute <unnamed>: SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, r.rngsubtype, t.typtype, t.typbasetype
        FROM pg_type as t
        LEFT JOIN pg_range as r ON oid = rngtypid
                      WHERE
                        t.typname IN ('int2', 'int4', 'int8', 'oid', 'float4', 'float8', 'text', 'varchar', 'char', 'name', 'bpchar', 'bool', 'bit', 'varbit', 'timestamptz', 'date', 'money', 'bytea', 'point', 'hstore', 'json', 'jsonb', 'cidr', 'inet', 'uuid', 'xml', 'tsvector', 'macaddr', 'citext', 'ltree', 'interval', 'path', 'line', 'polygon', 'circle', 'lseg', 'box', 'time', 'timestamp', 'numeric')
                        OR t.typtype IN ('r', 'e', 'd')
                        OR t.typinput::varchar = 'array_in'
                        OR t.typelem != 0

LOG:  statement: SHOW TIME ZONE
LOG:  statement: SELECT 1
LOG:  execute <unnamed>: SELECT COUNT(*)
        FROM pg_class c
        LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
        WHERE c.relkind IN ('r','v','m') -- (r)elation/table, (v)iew, (m)aterialized view
        AND c.relname = 'accounts'
        AND n.nspname = ANY (current_schemas(false))
```
2018-11-22 19:43:53 +09:00
Thomas Bianchini a6e0eeb862 Fixing an issue when parsing an opclass by allowing indexed column
in indexdef to be wrapped up by double quotes

    Fixes #34493.

    *Thomas Bianchini*
2018-11-21 14:29:19 +01:00
Eileen M. Uchitelle 536a190ab3
Merge pull request #34491 from rails/fix-query-cache-on-multiple-connections
Fix query cache for multiple connections
2018-11-21 07:59:13 -05:00
Eileen Uchitelle aec635dc2f Fix query cache for multiple connections
Currently the query cache is only aware of one handler so once we added
multiple databases switching on the handler we broke query cache for
those reading connections.

While #34054 is the proper fix, that fix is not straight forward and I
want to make sure that the query cache isn't just broken for all other
connections not in the main handler.
2018-11-20 17:48:48 -05:00
Eileen Uchitelle 5ce3e022ef Make connection handler per thread instead of per fiber
The connection handler was using the RuntimeRegistry which kind of
implies it's a per thread registry. But it's actually per fiber.

If you have an application that uses fibers and you're using multiple
databases, when you switch the connection handler to swap connections
new fibers running on the same thread used to get a different connection
id. This PR changes the code to actually use a thread so that we get
the same connection.

Fixes https://github.com/rails/rails/issues/30047

[Eileen M. Uchitelle, Aaron Patterson, & Arthur Neeves]
2018-11-20 16:02:40 -05:00
Aaron Patterson 023a840f5f
Merge pull request #33954 from febeling/inconsistent-assignment-has-many-through-33942
Fix handling of duplicates for `replace` on has_many-through
2018-11-20 09:26:55 -08:00
Aaron Patterson a95c2eca48
Merge pull request #34453 from bogdanvlviv/exercise-connected_to-and-connects_to
Exercise `connected_to` and `connects_to` methods
2018-11-19 13:26:35 -08:00
Jacob Evelyn b659b71e8e Fix typo and clarify documentation
This commit fixes a small typo in documentation of the
"UNLOGGED" table option for PostgreSQL databases, and
clarifies the documentation slightly.
2018-11-16 16:17:42 -05:00
Gannon McGibbon 236bfaf785 Fix cache_versioning default note (#34466)
[ci skip]
2018-11-16 15:44:16 -05:00
Dmytro Shteflyuk b5302d5a82 Arel: Implemented DB-aware NULL-safe comparison (#34451)
* Arel: Implemented DB-aware NULL-safe comparison

* Fixed where clause inversion for NULL-safe comparison

* Renaming "null_safe_eq" to "is_not_distinct_from", "null_safe_not_eq" to "is_distinct_from"

[Dmytro Shteflyuk + Rafael Mendonça França]
2018-11-15 14:49:55 -05:00
bogdanvlviv cf01da283e
Exercise `connected_to` and `connects_to` methods
Since both methods are public API I think it makes sense to add these tests
in order to prevent any regression in the behavior of those methods after the 6.0 release.

Exercise `connected_to`
  - Ensure that the method raises with both `database` and `role` arguments
  - Ensure that the method raises without `database` and `role`

Exercise `connects_to`
  - Ensure that the method returns an array of established connections(as mentioned
    in the docs of the method)

Related to #34052
2018-11-15 11:48:07 +02:00
Rafael Mendonça França 3dea7f0615
Merge pull request #34437 from kbrock/union_all_paren
Fix: Arel now emits a single pair of parens for UNION and UNION ALL
2018-11-13 17:37:05 -05:00
Keenan Brock 63dd8d8e12 Emit single pair of parens for UNION and UNION ALL
mysql has a great implementation to suppress multiple parens for union
sql statements.

This moves that functionality to the generic implementation
This also introduces that functionality for UNION ALL
2018-11-13 17:05:45 -05:00
Rafael França 5e9a3e7763
Merge pull request #34436 from gmcgibbon/fix_default_max_bind_length_sqlite
Adjust bind length of SQLite to default (999)
2018-11-13 15:37:51 -05:00
Gannon McGibbon 31efa2d9e1 Adjust bind length of SQLite to default (999)
Change `#bind_params_length` in SQLite adapter to return the default
maximum amount (999). See https://www.sqlite.org/limits.html
2018-11-13 15:15:15 -05:00
Jacob Evelyn bfc4d8be0a Add support for UNLOGGED Postgresql tables
This commit adds support for the
`ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.create_unlogged_tables`
setting, which turns `CREATE TABLE` SQL statements into
`CREATE UNLOGGED TABLE` statements.

This can improve PostgreSQL performance but at the
cost of data durability, and thus it is highly recommended
that you *DO NOT* enable this in a production environment.
2018-11-13 09:37:20 -05:00
Eugene Kenny d8a9bc02f3 Remove ensure from with_transaction_returning_status
The test added in 12b0b26df7 passes even
without this code since 9b8c7796a9, as the
call to `id` in `remember_transaction_record_state` now triggers a
`sync_with_transaction_state` which discards the leftover state from the
previous transaction.

This issue had already been fixed for `save!`, `destroy` and `touch` in
caae79a385, but continued to affect `save`
because the call to `rollback_active_record_state!` in that method would
increment the transaction level before `add_to_transaction` could clear
it, preventing the fix from working correctly.

As `rollback_active_record_state!` was removed entirely in
48007d5390, this code is no longer needed.
2018-11-11 22:35:47 +00:00
Ryuta Kamizono f4bc364fdf Deprecate `t.indexes = [...]` which is not by design
Use `t.index ...` instead.
2018-11-09 06:17:47 +09:00
Ryuta Kamizono b04c633964 Refactor to initialize `TableDefinition` by kwargs 2018-11-09 05:49:44 +09:00
Ryuta Kamizono 8623223a89 PostgreSQL: Properly quote all `Infinity` and `NaN`
Since quoted `Infinity` and `NaN` are valid data for PostgreSQL.
2018-11-09 00:05:39 +09:00
fatkodima 6e0ff00537 Add an :if_not_exists option to create_table
[fatkodima & Stefan Kanev]
2018-11-08 15:26:07 +02:00
Christophe Maximin 25f1cbdecd Guard Enums against definitions with blank label names 2018-11-07 23:36:39 +00:00
Gannon McGibbon ac18bda92d Add multi-db support to schema cache dump and clear
Adds support for multiple databases to `rails db:schema:cache:dump`
and `rails db:schema:cache:clear`.
2018-11-07 14:11:46 -05:00
Eugene Kenny 9030b7c775 Always add records to parent of nested transaction
When a record with transactional callbacks is saved, it's attached to
the current transaction so that the callbacks can be run when the
transaction is committed. Records can also be added manually with
`add_transaction_record`, even if they have no transactional callbacks.

When a nested transaction is committed, its records are transferred to
the parent transaction, as transactional callbacks should only be run
when the outermost transaction is committed (the "real" transaction).
However, this currently only happens when the record has transactional
callbacks, and not when added manually with `add_transaction_record`.

If a record is added to a nested transaction, we should always attach it
to the parent transaction when the nested transaction is committed,
regardless of whether it has any transactional callbacks.

[Eugene Kenny & Ryuta Kamizono]
2018-11-07 13:32:49 +00:00
Florian Ebeling f9157587c9 Optimize difference and intersection 2018-11-06 17:56:58 +01:00
Florian Ebeling 11bad94237 Rename union to intersection 2018-11-06 17:56:58 +01:00
Florian Ebeling 8104589c08 Fix handling of duplicates for `replace` on has_many-through
There was a bug in the handling of duplicates when
assigning (replacing) associated records, which made the result
dependent on whether a given record was associated already before
being assigned anew. E.g.

    post.people = [person, person]
    post.people.count
    # => 2

while

    post.people = [person]
    post.people = [person, person]
    post.people.count
    # => 1

This change adds a test to provoke the former incorrect behavior, and
fixes it.

Cause of the bug was the handling of record collections as sets, and
using `-` (difference) and `&` (union) operations on them
indiscriminately. This temporary conversion to sets would eliminate
duplicates.

The fix is to decorate record collections for these operations, and
only for the `has_many :through` case. It is done by counting
occurrences, and use the record together with the occurrence number as
element, in order to make them work well in sets. Given

    a, b = *Person.all

then the collection used for finding the difference or union of
records would be internally changed from

     [a, b, a]

to

     [[a, 1], [b, 1], [a, 2]]

for these operations. So a first occurrence and a second occurrence
would be distinguishable, which is all that is necessary for this
task.

Fixes #33942.
2018-11-06 17:56:58 +01:00
Eugene Kenny 65cd0fda25 Fix inspect with non-primary key id attribute
The `read_attribute` method always returns the primary key when asked to
read the `id` attribute, even if the primary key isn't named `id`, and
even if another attribute named `id` exists.

For the `inspect`, `attribute_for_inspect` and `pretty_print` methods,
this behaviour is undesirable, as they're used to examine the internal
state of the record. By using `_read_attribute` instead, we'll get the
real value of the `id` attribute.
2018-11-06 01:51:52 +00:00
Ryuta Kamizono 5821b1fd79 Move `resolve_sti_reflections` which is table row related code into `TableRow` 2018-11-03 23:39:54 +09:00
Ryuta Kamizono 06ef4c3fa8 Don't pass useless `table_name` to `ModelMetadata.new`
The `model_metadata` is only used if `model_class` is given.

If `model_class` is given, the `table_name` is always
`model_class.table_name`.
2018-11-03 22:35:23 +09:00
Ryuta Kamizono 1812240f1a Don't pass unused `connection` to `FixtureSet.new`
The `@connection` is no longer used since ee5ab22.

Originally the `@connection` was useless because it is only used in
`timestamp_column_names`, which is only used if `model_class` is given.

If `model_class` is given, the `@connection` is always
`model_class.connection`.
2018-11-03 21:38:19 +09:00
Ryuta Kamizono 19f0f14074 Checking boundable not only `IN` clause but also `NOT IN` clause 2018-11-03 14:54:57 +09:00
Espartaco Palma 676b0960bc
Updating sample code on ActiveRecord#before_destroy callback [ci skip]
It was executing a delete_all method with wrong parameter
2018-10-31 23:18:27 -07:00
Ryuta Kamizono b86c2a6767 Fix "warning: shadowing outer local variable - role"
Caused at #34196.
2018-10-31 12:04:20 +09:00
Rafael França 6b23b7e78c
Merge pull request #34353 from gmcgibbon/fix_lock_docs_locking_clause
Fix example for database-specific locking clause
2018-10-30 17:14:05 -04:00
Gannon McGibbon 6e2357f0fe Fix example for database-specific locking clause
[ci skip]
2018-10-30 16:58:57 -04:00
Sean Griffin 3b2ea8b683 Fix failing test
b63701e moved the assignment before the query, but we need to capture
our old id before assignment in case we are assigning the id.
2018-10-30 14:03:11 -06:00
Sean Griffin b63701e272 `update_columns` raises if the column is unknown
Previosly, `update_columns` would just take whatever keys you gave it
and tried to run the update query. Most likely this would result in an
error from the database. However, if the column actually did exist, but
was in `ignored_columns`, this would result in the method returning
successfully when it should have raised, and an attribute that should
not exist written to `@attributes`.
2018-10-30 12:52:23 -06:00
Ryuta Kamizono 9ae3ddbb21
Merge pull request #19388 from yakara-ltd/fix-habtm-fixture-order
Avoid violating key constraints in fixture HABTM associations
2018-10-30 22:04:19 +09:00
Eileen M. Uchitelle 6889e720cc Merge pull request #34196 from gmcgibbon/connection_switch_string_name
Add support for hash and url configs to be used in connected_to
2018-10-30 08:56:34 -04:00
James Le Cuirot cf1d75d95d Avoid violating key constraints in fixture HABTM associations
When loading fixtures, Ruby 1.9's hash key ordering means that HABTM
join table rows are always loaded before the parent table rows,
violating foreign key constraints that may be in place. This very
simple change ensures that the parent table's key appears first in the
hash. Violations may still occur if fixtures are loaded in the wrong
order but those instances can be avoided unlike this one.
2018-10-29 15:11:35 +00:00
Malcolm Locke 20ea01bd64 Document exception from restrict_with_exception [ci skip] 2018-10-29 15:12:29 +13:00
r7kamura 4694fcf413 Ignore empty condition on #construct_relation_for_exists
At fc0e3354af,

```rb
relation = relation.where(conditions)
```

was rewritten to:

```rb
relation.where!(condition)
```

This change accidentally changed the result of `Topic.exists?({})` from true to false.

To fix this regression, first I moved the blank check logic (`opts.blank?`) from `#where` to `#where!`,
because I thought `#where!` should be identical to `#where`, except that instead of returning a new relation,
it adds the condition to the existing relation.

But on second thought after some discussion on https://github.com/rails/rails/pull/34329,
I started to think that just fixing `#construct_relation_for_exists` is more preferable
than changing `#where` and `#where!`.
2018-10-27 21:53:11 +09:00
Gannon McGibbon abf51844bb Add support for hash and url configs in connected_to
Add support for hash and url configs in database hash
of `ActiveRecord::Base.connected_to`.
2018-10-26 16:27:25 -04:00
Ryuta Kamizono 61490805fe
Merge pull request #34208 from yskkin/inspect_with_parameter_filter
Implement AR#inspect using ParameterFilter
2018-10-26 19:05:34 +09:00
Ryuta Kamizono a2ad8f456e Support default expression for MySQL
MySQL 8.0.13 and higher supports default value to be a function or
expression.

https://dev.mysql.com/doc/refman/8.0/en/create-table.html
2018-10-25 18:11:22 +09:00
Ryuta Kamizono d496055b5b Support expression indexes for MySQL
MySQL 8.0.13 and higher supports functional key parts that index
expression values rather than column or column prefix values.

https://dev.mysql.com/doc/refman/8.0/en/create-index.html
2018-10-25 18:09:02 +09:00
Willian Gustavo Veiga b217e6e7d3 Avoid creating an extra relation instance 2018-10-24 20:29:13 -03:00
Rafael França d3e646595f
Merge pull request #34303 from kamipo/lazy_checking_boundable
Lazy checking whether or not values in IN clause are boundable
2018-10-24 12:53:37 -04:00
Ryuta Kamizono ce40073c9c Lazy checking whether or not values in IN clause are boundable
Since #33844, eager loading/preloading with too many and/or too large
ids won't be broken by pre-checking whether the value is constructable
or not.

But the pre-checking caused the type to be evaluated at relation build
time instead of at the query execution time, that is breaking an
expectation for some apps.

I've made the pre-cheking lazy as much as possible, that is no longer
happend at relation build time.
2018-10-24 11:26:49 +09:00
ohbarye 7217179d1e Fix typo of duplicated `the` [ci skip] 2018-10-24 01:16:02 +09:00
Francesco Rodríguez 0e038e1702
Hide PG::Connection from API docs [ci skip] 2018-10-23 14:54:31 +02:00
Yasuo Honda 26369bbebf MySQL 8.0.13 raises `ER_NO_REFERENCED_ROW` and `ER_ROW_IS_REFERENCED`
when user has no parent table access privileges

Refer https://dev.mysql.com/doc/relnotes/mysql/8.0/en/news-8-0-13.html#mysqld-8-0-13-errors

>>
* Previously, the ER_NO_REFERENCED_ROW_2 and ER_ROW_IS_REFERENCED_2 error messages
for foreign key operations were displayed and revealed information about parent tables,
even when the user had no parent table access privileges. Error handling for this situation has been revised:

  * If the user does have table-level privileges for all parent tables,
    ER_NO_REFERENCED_ROW_2 and ER_ROW_IS_REFERENCED_2 are displayed, the same as before.

  * If the user does not have table-level privileges for all parent tables,
    more generic error messages are displayed instead (ER_NO_REFERENCED_ROW and ER_ROW_IS_REFERENCED).
<<

This pull request addresses these 3 failures:

```ruby
$ ARCONN=mysql2 bundle exec ruby -w -Itest test/cases/adapter_test.rb -n /foreign/
Using mysql2
Run options: -n /foreign/ --seed 14251

F

Failure:
ActiveRecord::AdapterForeignKeyTest#test_foreign_key_violations_are_translated_to_specific_exception_with_validate_false [test/cases/adapter_test.rb:348]:
[ActiveRecord::InvalidForeignKey] exception expected, not
Class: <ActiveRecord::StatementInvalid>
Message: <"Mysql2::Error: Cannot add or update a child row: a foreign key constraint fails: INSERT INTO `fk_test_has_fk` (`fk_id`) VALUES (1231231231)">

... snip ...

rails test test/cases/adapter_test.rb:343

F

Failure:
ActiveRecord::AdapterForeignKeyTest#test_foreign_key_violations_on_delete_are_translated_to_specific_exception [test/cases/adapter_test.rb:368]:
[ActiveRecord::InvalidForeignKey] exception expected, not
Class: <ActiveRecord::StatementInvalid>
Message: <"Mysql2::Error: Cannot delete or update a parent row: a foreign key constraint fails: DELETE FROM fk_test_has_pk WHERE pk_id = 1">

... snip ...

rails test test/cases/adapter_test.rb:365

F

Failure:
ActiveRecord::AdapterForeignKeyTest#test_foreign_key_violations_on_insert_are_translated_to_specific_exception [test/cases/adapter_test.rb:358]:
[ActiveRecord::InvalidForeignKey] exception expected, not
Class: <ActiveRecord::StatementInvalid>
Message: <"Mysql2::Error: Cannot add or update a child row: a foreign key constraint fails: INSERT INTO fk_test_has_fk (fk_id) VALUES (0)">

... snip ...

rails test test/cases/adapter_test.rb:357

Finished in 0.087370s, 34.3366 runs/s, 34.3366 assertions/s.
3 runs, 3 assertions, 3 failures, 0 errors, 0 skips
$
```
2018-10-23 07:43:25 +00:00
Willian Gustavo Veiga 47ef6fd2ca Merge branch 'master' into feature/reselect-method 2018-10-22 20:06:45 -03:00
Eugene Kenny ffc9ed3d3b Reduce string allocations in read/write_attribute
When `attr_name` is passed as a symbol, it's currently converted to a
string by `attribute_alias?`, and potentially also `attribute_alias`,
as well as by the `read_attribute`/`write_attribute` method itself.

By converting `attr_name` to a string up front, the extra allocations
related to attribute aliases can be avoided.
2018-10-21 13:58:45 +02:00
Yoshiyuki Kinjo 32b03b4615 Implement AR#inspect using ParamterFilter.
AR instance support `filter_parameters` since #33756.
Though Regex or Proc is valid as `filter_parameters`,
they are not supported as AR#inspect.

I also add :mask option and #filter_params to
`ActiveSupport::ParameterFilter#new` to implement this.
2018-10-19 14:16:03 +09:00
Ryuta Kamizono aed7e00039 Don't expose internal `get_value`/`set_value` methods 2018-10-18 08:29:58 +09:00
Willian Gustavo Veiga c8ff9bd63a Merge branch 'master' into feature/reselect-method 2018-10-17 20:24:44 -03:00
lsylvester 73f9cd2da4 Prefer String#ljust over String#<< for padding 2018-10-17 11:06:08 -05:00
schneems 2f99da00c7 Do not silently fail to generate a cache_version
When an `updated_at` column exists on the model, but is not available on the instance (likely due to a select), we should raise an error rather than silently not generating a cache_version. Without this behavior it's likely that cache entries will not be able to be invalidated and this will happen without notice. 

This behavior was reported and described by @lsylvester in https://github.com/rails/rails/pull/34197#issuecomment-429668759.
2018-10-17 11:05:05 -05:00
schneems 04454839a1 Use raw time string from DB to generate ActiveRecord#cache_version
Currently, the `updated_at` field is used to generate a `cache_version`. Some database adapters return this timestamp value as a string that must then be converted to a Time value. This process requires a lot of memory and even more CPU time. In the case where this value is only being used for a cache version, we can skip the Time conversion by using the string value directly.

- This PR preserves existing cache format by converting a UTC string from the database to `:usec` format.
- Some databases return an already converted Time object, in those instances, we can directly use `created_at`.
- The `updated_at_before_type_cast` can be a value that comes from either the database or the user. We only want to optimize the case where it is from the database.
- If the format of the cache version has been changed, we cannot apply this optimization, and it is skipped.
- If the format of the time in the database is not UTC, then we cannot use this optimization, and it is skipped.

Some databases (notably PostgreSQL) returns a variable length nanosecond value in the time string. If the value ends in a zero, then it is truncated For instance instead of `2018-10-12 05:00:00.000000` the value `2018-10-12 05:00:00` is returned. We detect this case and pad the remaining zeros to ensure consistent cache version generation.

Before: Total allocated: 743842 bytes (6626 objects)
After: Total allocated: 702955 bytes (6063 objects)

(743842 - 702955) / 743842.0 # => 5.4% ️

Using the CodeTriage application and derailed benchmarks this PR shows between 9-11% (statistically significant) performance improvement versus the commit before it.

Special thanks to @lsylvester for helping to figure out a way to preserve the usec format and for helping with many implementation details.
2018-10-17 11:05:05 -05:00
Richard Schneeman ead868315f
Merge pull request #34197 from schneems/schneems/symbol-hash-respond_to
ActiveRecord#respond_to? No longer allocates strings
2018-10-17 09:17:48 -05:00
Ryuta Kamizono 12c7b101f8 Remove and flip `index: true` for `references` in the doc [ci skip]
Follow up #32146.
2018-10-17 21:43:23 +09:00
Ryuta Kamizono 1198a3880b Consolidate duplicated code that initializing an empty model object
`init_with` and `init_from_db` are almost the same code except decode
`coder`.

And also, named `init_from_db` is a little misreading, a raw values hash
from the database is already converted to an attributes object by
`attributes_builder.build_from_database`, so passed `attributes` in that
method is just an attributes object.

I renamed that method to `init_with_attributes` since the method is
shared with `init_with` to initialize an empty model object.
2018-10-17 10:51:53 +09:00
Ryuta Kamizono 5b5367364f Consistently extract checking version for all adapters
I don't prefer to extract it for one adapter even though all adapters
also does.

Related to #34227.
2018-10-17 07:24:17 +09:00
Aaron Patterson e53acfde0f
Merge pull request #34227 from bkuhlmann/master-lazy_mysql_version_check_support
Refactored abstract MySQL adapter to support lazy version check.
2018-10-16 13:34:41 -07:00
Brooke Kuhlmann e1f6821105 Refactored abstract MySQL adapter to support lazy version check.
Will allow sub classes to override the protected
`#check_version` method hook if desired.

For example, this will be most helpful in sub classes that wish
to support lazy initialization because the version check can
be postponed until the connection is ready to be initialized.
2018-10-16 10:09:06 -06:00
Federico Martinez b1aeae0494 Fix Collection cache key with limit and custom select (PG:AmbigousColumn: Error)
Change query to use alias name for timestamp_column to avoid ambiguity problems when using timestamp from subquery.
2018-10-15 20:38:12 -03:00
schneems f45267bc42 ActiveRecord#respond_to? No longer allocates strings
This is an alternative to https://github.com/rails/rails/pull/34195

The active record `respond_to?` method needs to do two things if `super` does not say that the method exists. It has to see if the "name" being passed in represents a column in the table. If it does then it needs to pass it to `has_attribute?` to see if the key exists in the current object. The reason why this is slow is that `has_attribute?` needs a string and most (almost all) objects passed in are symbols.

The only time we need to allocate a string in this method is if the column does exist in the database, and since these are a limited number of strings (since column names are a finite set) then we can pre-generate all of them and use the same string. 

We generate a list hash of column names and convert them to symbols, and store the value as the string name. This allows us to both check if the "name" exists as a column, but also provides us with a string object we can use for the `has_attribute?` call. 

I then ran the test suite and found there was only one case where we're intentionally passing in a string and changed it to a symbol. (However there are tests where we are using a string key, but they don't ship with rails).

As re-written this method should never allocate unless the user passes in a string key, which is fairly uncommon with `respond_to?`.

This also eliminates the need to special case every common item that might come through the method via the `case` that was originally added in f80aa59946 (by me) and then with an attempt to extend in https://github.com/rails/rails/pull/34195.

As a bonus this reduces 6,300 comparisons (in the CodeTriage app homepage) to 450 as we also no longer need to loop through the column array to check for an `include?`.
2018-10-15 15:31:32 -05:00
Dylan Thacker-Smith 99c87ad247 Improve model attribute accessor method names for backtraces
Ruby uses the original method name, so will show the __temp__ method
name in the backtrace. However, in the common case the method name
is compatible with the `def` keyword, so we can avoid the __temp__
method name in that case to improve the name shown in backtraces
or TracePoint#method_id.
2018-10-12 09:50:10 -07:00
Willian Gustavo Veiga 99bd626885 Merge branch 'master' into feature/reselect-method 2018-10-11 07:44:27 -03:00
Eileen Uchitelle 31021a8c85 Basic API for connection switching
This PR adds the ability to 1) connect to multiple databases in a model,
and 2) switch between those connections using a block.

To connect a model to a set of databases for writing and reading use
the following API. This API supercedes `establish_connection`. The
`writing` and `reading` keys represent handler / role names and
`animals` and `animals_replica` represents the database key to look up
the configuration hash from.

```
class AnimalsBase < ApplicationRecord
  connects_to database: { writing: :animals, reading: :animals_replica }
end
```

Inside the application - outside the model declaration - we can switch
connections with a block call to `connected_to`.

If we want to connect to a db that isn't default (ie readonly_slow) we
can connect like this:

Outside the model we may want to connect to a new database (one that is
not in the default writing/reading set) - for example a slow replica for
making slow queries. To do this we have the `connected_to` method that
takes a `database` hash that matches the signature of `connects_to`. The
`connected_to` method also takes a block.

```
AcitveRecord::Base.connected_to(database: { slow_readonly: :primary_replica_slow }) do
  ModelInPrimary.do_something_thats_slow
end
```

For models that are already loaded and connections that are already
connected, `connected_to` doesn't need to pass in a `database` because
you may want to run queries against multiple databases using a specific
role/handler.

In this case `connected_to` can take a `role` and use that to swap on
the connection passed. This simplies queries - and matches how we do it
in GitHub. Once you're connected to the database you don't need to
re-connect, we assume the connection is in the pool and simply pass the
handler we'd like to swap on.

```
ActiveRecord::Base.connected_to(role: :reading) do
  Dog.read_something_from_dog
  ModelInPrimary.do_something_from_model_in_primary
end
```
2018-10-10 12:13:46 -04:00
Eileen M. Uchitelle 58999af99f
Merge pull request #34110 from albertoalmagro/enum-raises-on-invalid-definition-values
Enum raises on invalid definition values
2018-10-10 11:42:41 -04:00
Eileen M. Uchitelle 9413ef56e5
Merge pull request #34137 from gmcgibbon/db_migrate_status_multi_db
Add multi-db support to rails db:migrate:status
2018-10-10 11:41:42 -04:00
Alberto Almagro df11558942 Privatize ENUM_CONFLICT_MESSAGE constant 2018-10-10 10:22:10 +02:00
Alberto Almagro 9b9640112e Raise on invalid definition values
When defining a Hash enum it can be easy to use [] instead of {}. This
commit checks that only valid definition values are provided, those can
be a Hash, an array of Symbols or an array of Strings. Otherwise it
raises an ArgumentError.

Fixes #33961
2018-10-10 10:22:07 +02:00
Ryuta Kamizono a52c6989a0
Merge pull request #34122 from kamipo/generate_relation_methods
Generate delegation methods to named scope in the definition time
2018-10-10 16:59:21 +09:00
Ryuta Kamizono 6c69a96048
Merge pull request #34094 from christophemaximin/fix-activerecord-clearing-of-query-cache
Fix inconsistent behavior by clearing QueryCache when reloading associations
2018-10-10 16:51:14 +09:00
Christophe Maximin 961776832d Clear QueryCache when reloading associations 2018-10-10 00:17:05 +01:00
Ryuta Kamizono e0d147fa90 Fix odd indentation 2018-10-10 08:03:06 +09:00
Ryuta Kamizono f569955e06 Refactor Arel visitor to use `collect_nodes_for` as much as possible 2018-10-10 06:48:20 +09:00
Gannon McGibbon 287c0de8a1 Add multi-db support to rails db:migrate:status 2018-10-09 16:40:06 -04:00
Ryuta Kamizono 92ccb7c75f Improve DELETE with JOIN handling to avoid subqueries if possible
Before:

```
  Pet Destroy (0.8ms)  DELETE FROM `pets` WHERE `pets`.`pet_id` IN (SELECT `pet_id` FROM (SELECT DISTINCT `pets`.`pet_id` FROM `pets` LEFT OUTER JOIN `toys` ON `toys`.`pet_id` = `pets`.`pet_id` WHERE `toys`.`name` = ?) AS __active_record_temp)  [["name", "Bone"]]
```

After:

```
  Pet Destroy (1.0ms)  DELETE `pets` FROM `pets` LEFT OUTER JOIN `toys` ON `toys`.`pet_id` = `pets`.`pet_id` WHERE `toys`.`name` = ?  [["name", "Bone"]]
```
2018-10-10 05:31:20 +09:00
Eileen M. Uchitelle 1ddfee9d11
Merge pull request #34081 from gmcgibbon/db_migrate_status_move
Move db:migrate:status to DatabaseTasks method
2018-10-09 14:34:26 -04:00
Ryuta Kamizono 82ac2114a1
Merge pull request #34117 from aergonaut/docs/ActiveRecord--Persistence-belongs_to_touch_method
Add docs to ActiveRecord::Persistence#belongs_to_touch_method

[ci skip]
2018-10-10 02:38:56 +09:00
Ryuta Kamizono 136b738cd2 Generate delegation methods to named scope in the definition time
The delegation methods to named scope are defined when `method_missing`
is invoked on the relation.

Since #29301, the receiver in the named scope is changed to the relation
like others (e.g. `default_scope`, etc) for consistency.

Most named scopes would be delegated from relation by `method_missing`,
since we don't allow scopes to be defined which conflict with instance
methods on `Relation` (#31179). But if a named scope is defined with the
same name as any method on the `superclass` (e.g. `Kernel.open`), the
`method_missing` on the relation is not invoked.

To address the issue, make the delegation methods to named scope is
generated in the definition time.

Fixes #34098.
2018-10-09 13:03:08 +09:00
Gannon McGibbon 0d435c17b7 Move db:migrate:status to DatabaseTasks method 2018-10-08 13:46:01 -04:00
Francesco Rodríguez 673e33eee5
[ci skip] Fix typo 2018-10-08 08:32:56 +02:00
Chris Fung 3969de3e87
Add docs to ActiveRecord::Persistence#belongs_to_touch_method
[ci skip]
2018-10-07 14:12:06 -07:00
Ryuta Kamizono 0b4cfa2ba3 Don't expose internal methods in the associations 2018-10-08 00:12:28 +09:00