We should set the `@records` and `@loaded` ivar inside `#load` rather
than in `#exec_queries`. Since `#load` is running `#exec_queries` and
`@records` can only be assigned if `loaded?` is true and `@loaded` can
only be set if `loaded?` is true then `#load` should do the assignment.
This is cleaner but also we came across this while working on an
internal gem and realized that the ivar assignment was happening in the
wrong place.
Co-authored-by: Aaron Patterson <aaron.patterson@gmail.com>
In https://github.com/rails/rails/pull/36388,
we supported passing objects that `respond_to` `render_in`
to `render`, but _only_ in views.
This change does the same for controllers, as Rails
generally gives the expectation that `render` behaves
the same in both contexts.
Co-authored-by: Aaron Patterson <tenderlove@github.com>
As a follow-up to https://github.com/rails/rails/pull/37872,
this change introduces a class_names view helper
to make it easier to conditionally apply class names
in views.
Before:
<div class="<%= item.for_sale? ? 'active' : '' %>">
After:
<div class="<%= class_names(active: item.for_sale?) %>">
We've been using this helper in the GitHub monolith
since 2016.
Co-authored-by: Aaron Patterson <tenderlove@github.com>
- #37872 introduced a regression and you can't do
```html.erb
hidden_field_tag('token', value: [1, 2, 3])
```
This will result in a `<input type="hidden" value=""`>.
I chose `hidden_field_tag` and the `value` attribute as an example
but this issue applies to any tag helper and any attributes.
https://github.com/rails/rails/pull/37872#issuecomment-561806468
mention that the feature should only apply for "class" attribute.
This commit fix original intent of #37872
A querystring value should be allowed to include an equal sign `=`.
This is necessary to support passing `options` for a PostgresSQL connection.
```
development:
url: postgresql://localhost/railsdevapp_development?options=-cmysetting.debug=on
```
Before this PR, attempting to start the rails process with that configuration would result in an error:
```
> bundle exec rails console
Traceback (most recent call last):
49: from bin/rails:4:in `<main>'
48: from bin/rails:4:in `require'
...
1: from /rails/activerecord/lib/active_record/database_configurations/connection_url_resolver.rb:58:in `query_hash'
/rails/activerecord/lib/active_record/database_configurations/connection_url_resolver.rb:58:in `[]': invalid number of elements (3 for 1..2) (ArgumentError)
```
After this PR, rails can properly parse the configuration:
```
> bundle exec rails console
Loading development environment (Rails 6.1.0.alpha)
2.6.5 :001 > ActiveRecord::Base.connection.select_all("show mysetting.debug").to_a
(0.4ms) show mysetting.debug
=> [{"mysetting.debug"=>"on"}]
```
- ### Problem
```ruby
MyJob < ApplicationJob
before_enqueue { throw(:abort) }
after_enqueue { # enters here }
end
```
I find AJ behaviour on after_enqueue and after_perform callbacks
weird as they get run even when the callback chain is halted.
It's counter intuitive to run the after_enqueue callbacks even
though the job wasn't event enqueued.
### Solution
In Rails 6.2, I propose to make the new behaviour the default
and stop running after callbacks when the chain is halted.
For application that wants this behaviour now or in 6.1
they can do so by adding the `config.active_job.skip_after_callbacks_if_terminated = true`
in their configuration file.
- ### Problem
ActiveJob will always log "Enqueued MyJob (Job ID) ..." even
if the job doesn't get enqueued through the adapter.
Same problem happens when performing a Job, "Performed MyJob (Job ID) ..." will be logged even when job wasn't performed at all.
This situation can happen either if the callback chain is terminated
(before_enqueue throwing an `abort`) or if an exception is raised.
### Solution
Check if the callback chain is aborted/exception is raised, and log accordingly.
- SQlite allow database to be specified as URL (given that URI filename
interpretation was turned on on the connection.)
This commit is necessary for the read_uncommitted transaction
feature because SQLite doesn't allow to enable the shared-cache mode
if the database name is `:memory:`. It has to be a URI (`file::memory`)
Ref https://www.sqlite.org/sharedcache.html#shared_cache_and_in_memory_databases
- ### Use case
I'd like to be able to see changes made by a connection writer
within a connection reader before the writer transaction commits
(aka `read_uncommitted` transaction isolation level).
```ruby
conn1.transaction do
Dog.create(name: 'Fido')
conn2.transaction do
Dog.find(name: 'Fido') # -> Can't see the dog untill conn1 commits the transaction
end
end
```
Other adapters in Rails (mysql, postgres) already supports multiple
types of isolated db transaction.
SQLite doesn't support the 4 main ones but it supports
`read_uncommitted` and `serializable` (the default one when opening
a transaction)
### Solution
This PR allow developers to open a `read_uncommitted` transaction by
setting the PRAGMA `read_uncommitted` to true for the duration
of the transaction. That PRAGMA can only be enabled if the SQLite
connection was established with the [shared-cache mode](https://www.sqlite.org/sharedcache.html)
This feature can also benefit the framework and we could potentially
get rid of the `setup_shared_connection_pool` inside tests which
was a solution in the context of a multi-db app so that the reader
can see stuff from the open transaction writer but has some [caveats](https://github.com/rails/rails/issues/37765#event-2828609021).
### Edge case
Shared-cache mode can be enabled for in memory database as well,
however for backward compatibility reasons, SQLite only allows
to set the shared-cache mode if the database name is a URI.
It won't allow it if the database name is `:memory`; it has to be
changed to `file::memory` instead.