new in rails 6 I'm interested in
Published: 2023-12-08 02:14:18

## add support for setting Optimizer Hints on databases

allow to pass pg_hint_plan for PostgreSQL:
```
Topic.optimizer_hints("SeqScan(topics)", "Parallel(topics 8)")
# SELECT /*+ SeqScan(topics) Parallel(topics 8) */ "topics".* FROM "topics"
```

for pg_hint_plan: https://postgrespro.com/docs/enterprise/9.6/pg-hint-plan

## Add negative scopes for all enum values

no need gem to add scopes for enum
```
class Post < ActiveRecord::Base
  enum status: %i[ drafted active trashed ]
end

Post.drafted # => where(status: :drafted)
Post.not_drafted # => where.not(status: :drafted)
```
if you don't want the scopes, add `_scopes: false` 

## automatically switch primary/replica database

for example:
A request will be sent to the replica if:
- The request is a read request (GET or HEAD)
- AND It's been 5 seconds since the last write to the database

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 5 seconds since the last write to the database

## block writes to a database

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

ActiveRecord::Base.connected_to(role: :reading) do
  Dog.connection.while_blocking_writes do
    Dog.first # will not raise because we're not writing
  end
end
```

## switching connect to Multi db

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

specify the role
```
ActiveRecord::Base.connected_to(role: :reading) do
  Dog.first # finds dog from replica connected to AnimalsBase
  Book.first # doesn't have a reading connection, will raise an error
end
```

specify the database
```
ActiveRecord::Base.connected_to(database: :slow_replica) do
  SlowReplicaModel.first # if the db config has a slow_replica configuration this will be used to do the lookup, otherwise this will throw an exception
end
```

## support ruby 2.6 endless ranges in where

```
relation.where(column: (1..))
same as
relation.where(column: 1..Float::INFINITY)
```

## override the implicit order column

when calling `first` or `last` without `order`, ActiveRecord will sort records by primary key, if your primary key is not integer, eg: uuid. you probably need this
```
class Project < ActiveRecord::Base
  self.implicit_order_column = "created_at"
end
```

## create_table if if_not_exists

```
create_table :posts, if_not_exists: true do |t|
  t.string :title
end
``` 

## rake db tasks

```
# support for multiple databases 
rails db:schema:cache:dump
rails db:schema:cache:clear
```

## mask sensitive data in #inspect
```
class Account < ActiveRecord::Base
  self.filter_attributes = [:credit_card_number]
end
```

set config.filter_parameters also mask the column
```
Rails.application.config.filter_parameters += [:credit_card_number]
Account.last.insepct # => #<Account id: 123, credit_card_number: [FILTERED]
```

also see ActiveSupport::ParameterFilter


## customize format of ActiveModel::Errors#full_message

eg: we want `#{message}` not `#{attribute} #{message}`
```
en:
  activemodel:
    errors:
      models:
        user:
          format: '%{message}'

user.errors.full_messages
=> ["Email email_required", "Email invalid_email"]

```

## index_with mapper

if we want map something to hash, we need
```
POST_ATTRIBUTES.map { |attr_name| [ attr_name, public_send(attr_name) ] }.to_h
```
now with `index_with`
```
POST_ATTRIBUTES.index_with { |attr_name| public_send(attr_name) }
```