gems rails 7.0.0

latest releases: 7.1.3.2, 7.1.3.1, 7.0.8.1...
2 years ago

Action Cable

  • The Action Cable client now ensures successful channel subscriptions:

    • The client maintains a set of pending subscriptions until either
      the server confirms the subscription or the channel is torn down.
    • Rectifies the race condition where an unsubscribe is rapidly followed
      by a subscribe (on the same channel identifier) and the requests are
      handled out of order by the ActionCable server, thereby ignoring the
      subscribe command.

    Daniel Spinosa

  • Compile ESM package that can be used directly in the browser as actioncable.esm.js.

    DHH

  • Move action_cable.js to actioncable.js to match naming convention used for other Rails frameworks, and use JS console to communicate the deprecation.

    DHH

  • Stop transpiling the UMD package generated as actioncable.js and drop the IE11 testing that relied on that.

    DHH

  • Truncate broadcast logging messages.

    J Smith

  • OpenSSL constants are now used for Digest computations.

    Dirkjan Bussink

  • The Action Cable client now includes safeguards to prevent a "thundering
    herd" of client reconnects after server connectivity loss:

    • The client will wait a random amount between 1x and 3x of the stale
      threshold after the server's last ping before making the first
      reconnection attempt.
    • Subsequent reconnection attempts now use exponential backoff instead of
      logarithmic backoff. To allow the delay between reconnection attempts to
      increase slowly at first, the default exponentiation base is < 2.
    • Random jitter is applied to each delay between reconnection attempts.

    Jonathan Hefner

Action Mailbox

  • Removed deprecated environment variable MAILGUN_INGRESS_API_KEY.

    Rafael Mendonça França

  • Removed deprecated Rails.application.credentials.action_mailbox.mailgun_api_key.

    Rafael Mendonça França

  • Add attachments to the list of permitted parameters for inbound emails conductor.

    When using the conductor to test inbound emails with attachments, this prevents an
    unpermitted parameter warning in default configurations, and prevents errors for
    applications that set:

    config.action_controller.action_on_unpermitted_parameters = :raise

    David Jones, Dana Henke

  • Add ability to configure ActiveStorage service
    for storing email raw source.

    # config/storage.yml
    incoming_emails:
      service: Disk
      root: /secure/dir/for/emails/only
    config.action_mailbox.storage_service = :incoming_emails

    Yurii Rashkovskii

  • Add ability to incinerate an inbound message through the conductor interface.

    Santiago Bartesaghi

  • OpenSSL constants are now used for Digest computations.

    Dirkjan Bussink

Action Mailer

  • Remove deprecated ActionMailer::DeliveryJob and ActionMailer::Parameterized::DeliveryJob
    in favor of ActionMailer::MailDeliveryJob.

    Rafael Mendonça França

  • email_address_with_name returns just the address if name is blank.

    Thomas Hutterer

  • Configures a default of 5 for both open_timeout and read_timeout for SMTP Settings.

    André Luis Leal Cardoso Junior

Action Pack

  • Deprecate Rails.application.config.action_controller.urlsafe_csrf_tokens. This config is now always enabled.

    Étienne Barrié

  • Instance variables set in requests in a ActionController::TestCase are now cleared before the next request

    This means if you make multiple requests in the same test, instance variables set in the first request will
    not persist into the second one. (It's not recommended to make multiple requests in the same test.)

    Alex Ghiculescu

  • Rails.application.executor hooks can now be called around every request in a ActionController::TestCase

    This helps to better simulate request or job local state being reset between requests and prevent state
    leaking from one request to another.

    To enable this, set config.active_support.executor_around_test_case = true (this is the default in Rails 7).

    Alex Ghiculescu

  • Consider onion services secure for cookies.

    Justin Tracey

  • Remove deprecated Rails.config.action_view.raise_on_missing_translations.

    Rafael Mendonça França

  • Remove deprecated support to passing a path to fixture_file_upload relative to fixture_path.

    Rafael Mendonça França

  • Remove deprecated ActionDispatch::SystemTestCase#host!.

    Rafael Mendonça França

  • Remove deprecated Rails.config.action_dispatch.hosts_response_app.

    Rafael Mendonça França

  • Remove deprecated ActionDispatch::Response.return_only_media_type_on_content_type.

    Rafael Mendonça França

  • Raise ActionController::Redirecting::UnsafeRedirectError for unsafe redirect_to redirects.

    This allows rescue_from to be used to add a default fallback route:

    rescue_from ActionController::Redirecting::UnsafeRedirectError do
      redirect_to root_url
    end

    Kasper Timm Hansen, Chris Oliver

  • Add url_from to verify a redirect location is internal.

    Takes the open redirect protection from redirect_to so users can wrap a
    param, and fall back to an alternate redirect URL when the param provided
    one is unsafe.

    def create
      redirect_to url_from(params[:redirect_url]) || root_url
    end

    dmcge, Kasper Timm Hansen

  • Allow Capybara driver name overrides in SystemTestCase::driven_by

    Allow users to prevent conflicts among drivers that use the same driver
    type (selenium, poltergeist, webkit, rack test).

    Fixes #42502

    Chris LaRose

  • Allow multiline to be passed in routes when using wildcard segments.

    Previously routes with newlines weren't detected when using wildcard segments, returning
    a No route matches error.
    After this change, routes with newlines are detected on wildcard segments. Example

      draw do
        get "/wildcard/*wildcard_segment", to: SimpleApp.new("foo#index"), as: :wildcard
      end
    
      # After the change, the path matches.
      assert_equal "/wildcard/a%0Anewline", url_helpers.wildcard_path(wildcard_segment: "a\nnewline")

    Fixes #39103

    Ignacio Chiazzo

  • Treat html suffix in controller translation.

    Rui Onodera, Gavin Miller

  • Allow permitting numeric params.

    Previously it was impossible to permit different fields on numeric parameters.
    After this change you can specify different fields for each numbered parameter.
    For example params like,

    book: {
            authors_attributes: {
              '0': { name: "William Shakespeare", age_of_death: "52" },
              '1': { name: "Unattributed Assistant" },
              '2': "Not a hash",
              'new_record': { name: "Some name" }
            }
          }

    Before you could permit name on each author with,
    permit book: { authors_attributes: [ :name ] }

    After this change you can permit different keys on each numbered element,
    permit book: { authors_attributes: { '1': [ :name ], '0': [ :name, :age_of_death ] } }

    Fixes #41625

    Adam Hess

  • Update HostAuthorization middleware to render debug info only
    when config.consider_all_requests_local is set to true.

    Also, blocked host info is always logged with level error.

    Fixes #42813

    Nikita Vyrko

  • Add Server-Timing middleware

    Server-Timing specification defines how the server can communicate to browsers performance metrics
    about the request it is responding to.

    The ServerTiming middleware is enabled by default on development environment by default using the
    config.server_timing setting and set the relevant duration metrics in the Server-Timing header

    The full specification for Server-Timing header can be found in: https://www.w3.org/TR/server-timing/#dfn-server-timing-header-field

    Sebastian Sogamoso, Guillermo Iguaran

  • Use a static error message when raising ActionDispatch::Http::Parameters::ParseError
    to avoid inadvertently logging the HTTP request body at the fatal level when it contains
    malformed JSON.

    Fixes #41145

    Aaron Lahey

  • Add Middleware#delete! to delete middleware or raise if not found.

    Middleware#delete! works just like Middleware#delete but will
    raise an error if the middleware isn't found.

    Alex Ghiculescu, Petrik de Heus, Junichi Sato

  • Raise error on unpermitted open redirects.

    Add allow_other_host options to redirect_to.
    Opt in to this behaviour with ActionController::Base.raise_on_open_redirects = true.

    Gannon McGibbon

  • Deprecate poltergeist and webkit (capybara-webkit) driver registration for system testing (they will be removed in Rails 7.1). Add cuprite instead.

    Poltergeist and capybara-webkit are already not maintained. These usage in Rails are removed for avoiding confusing users.

    Cuprite is a good alternative to Poltergeist. Some guide descriptions are replaced from Poltergeist to Cuprite.

    Yusuke Iwaki

  • Exclude additional flash types from ActionController::Base.action_methods.

    Ensures that additional flash types defined on ActionController::Base subclasses
    are not listed as actions on that controller.

    class MyController < ApplicationController
      add_flash_types :hype
    end
    
    MyController.action_methods.include?('hype') # => false
    

    Gavin Morrice

  • OpenSSL constants are now used for Digest computations.

    Dirkjan Bussink

  • Remove IE6-7-8 file download related hack/fix from ActionController::DataStreaming module.

    Due to the age of those versions of IE this fix is no longer relevant, more importantly it creates an edge-case for unexpected Cache-Control headers.

    Tadas Sasnauskas

  • Configuration setting to skip logging an uncaught exception backtrace when the exception is
    present in rescued_responses.

    It may be too noisy to get all backtraces logged for applications that manage uncaught
    exceptions via rescued_responses and exceptions_app.
    config.action_dispatch.log_rescued_responses (defaults to true) can be set to false in
    this case, so that only exceptions not found in rescued_responses will be logged.

    Alexander Azarov, Mike Dalessio

  • Ignore file fixtures on db:fixtures:load.

    Kevin Sjöberg

  • Fix ActionController::Live controller test deadlocks by removing the body buffer size limit for tests.

    Dylan Thacker-Smith

  • New ActionController::ConditionalGet#no_store method to set HTTP cache control no-store directive.

    Tadas Sasnauskas

  • Drop support for the SERVER_ADDR header.

    Following up rack/rack#1573 and #42349.

    Ricardo Díaz

  • Set session options when initializing a basic session.

    Gannon McGibbon

  • Add cache_control: {} option to fresh_when and stale?.

    Works as a shortcut to set response.cache_control with the above methods.

    Jacopo Beschi

  • Writing into a disabled session will now raise an error.

    Previously when no session store was set, writing into the session would silently fail.

    Jean Boussier

  • Add support for 'require-trusted-types-for' and 'trusted-types' headers.

    Fixes #42034.

    lfalcao

  • Remove inline styles and address basic accessibility issues on rescue templates.

    Jacob Herrington

  • Add support for 'private, no-store' Cache-Control headers.

    Previously, 'no-store' was exclusive; no other directives could be specified.

    Alex Smith

  • Expand payload of unpermitted_parameters.action_controller instrumentation to allow subscribers to
    know which controller action received unpermitted parameters.

    bbuchalter

  • Add ActionController::Live#send_stream that makes it more convenient to send generated streams:

    send_stream(filename: "subscribers.csv") do |stream|
      stream.writeln "email_address,updated_at"
    
      @subscribers.find_each do |subscriber|
        stream.writeln [ subscriber.email_address, subscriber.updated_at ].join(",")
      end
    end

    DHH

  • Add ActionController::Live::Buffer#writeln to write a line to the stream with a newline included.

    DHH

  • ActionDispatch::Request#content_type now returned Content-Type header as it is.

    Previously, ActionDispatch::Request#content_type returned value does NOT contain charset part.
    This behavior changed to returned Content-Type header containing charset part as it is.

    If you want just MIME type, please use ActionDispatch::Request#media_type instead.

    Before:

    request = ActionDispatch::Request.new("CONTENT_TYPE" => "text/csv; header=present; charset=utf-16", "REQUEST_METHOD" => "GET")
    request.content_type #=> "text/csv"

    After:

    request = ActionDispatch::Request.new("Content-Type" => "text/csv; header=present; charset=utf-16", "REQUEST_METHOD" => "GET")
    request.content_type #=> "text/csv; header=present; charset=utf-16"
    request.media_type   #=> "text/csv"

    Rafael Mendonça França

  • Change ActionDispatch::Request#media_type to return nil when the request don't have a Content-Type header.

    Rafael Mendonça França

  • Fix error in ActionController::LogSubscriber that would happen when throwing inside a controller action.

    Janko Marohnić

  • Allow anything with #to_str (like Addressable::URI) as a redirect_to location.

    ojab

  • Change the request method to a GET when passing failed requests down to config.exceptions_app.

    Alex Robbin

  • Deprecate the ability to assign a single value to config.action_dispatch.trusted_proxies
    as RemoteIp middleware behaves inconsistently depending on whether this is configured
    with a single value or an enumerable.

    Fixes #40772.

    Christian Sutter

  • Add redirect_back_or_to(fallback_location, **) as a more aesthetically pleasing version of redirect_back fallback_location:, **.
    The old method name is retained without explicit deprecation.

    DHH

Action Text

  • Fix an issue with how nested lists were displayed when converting to plain text

    Matt Swanson

  • Allow passing in a custom direct_upload_url or blob_url_template to rich_text_area_tag.

    Lucas Mansur

  • Make the Action Text + Trix JavaScript and CSS available through the asset pipeline.

    DHH

  • OpenSSL constants are now used for Digest computations.

    Dirkjan Bussink

  • Add support for passing form: option to rich_text_area_tag and
    rich_text_area helpers to specify the <input type="hidden" form="...">
    value.

    Sean Doyle

  • Add config.action_text.attachment_tag_name, to specify the HTML tag that contains attachments.

    Mark VanLandingham

  • Expose how we render the HTML surrounding rich text content as an
    extensible layouts/action_view/contents/_content.html.erb template to
    encourage user-land customizations, while retaining private API control over how
    the rich text itself is rendered by action_text/contents/_content.html.erb
    partial.

    Sean Doyle

  • Add with_all_rich_text method to eager load all rich text associations on a model at once.

    Matt Swanson, DHH

Action View

  • Support include_hidden: option in calls to
    ActionView::Helper::FormBuilder#file_field with multiple: true to
    support submitting an empty collection of files.

    form.file_field :attachments, multiple: true
    # => <input type="hidden" autocomplete="off" name="post[attachments][]" value="">
         <input type="file" multiple="multiple" id="post_attachments" name="post[attachments][]">
    
    form.file_field :attachments, multiple: true, include_hidden: false
    # => <input type="file" multiple="multiple" id="post_attachments" name="post[attachments][]">

    Sean Doyle

  • Fix number_with_precision(raise: true) always raising even on valid numbers.

    Pedro Moreira

  • Support fields model: [@nested, @model] the same way as form_with model: [@nested, @model].

    Sean Doyle

  • Infer HTTP verb [method] from a model or Array with model as the first
    argument to button_to when combined with a block:

    button_to(Workshop.find(1)){ "Update" }
    #=> <form method="post" action="/workshops/1" class="button_to">
    #=>   <input type="hidden" name="_method" value="patch" autocomplete="off" />
    #=>   <button type="submit">Update</button>
    #=> </form>
    
    button_to([ Workshop.find(1), Session.find(1) ]) { "Update" }
    #=> <form method="post" action="/workshops/1/sessions/1" class="button_to">
    #=>   <input type="hidden" name="_method" value="patch" autocomplete="off" />
    #=>   <button type="submit">Update</button>
    #=> </form>

    Sean Doyle

  • Support passing a Symbol as the first argument to FormBuilder#button:

    form.button(:draft, value: true)
    # => <button name="post[draft]" value="true" type="submit">Create post</button>
    
    form.button(:draft, value: true) do
      content_tag(:strong, "Save as draft")
    end
    # =>  <button name="post[draft]" value="true" type="submit">
    #       <strong>Save as draft</strong>
    #     </button>

    Sean Doyle

  • Introduce the field_name view helper, along with the
    FormBuilder#field_name counterpart:

    form_for @post do |f|
      f.field_tag :tag, name: f.field_name(:tag, multiple: true)
      # => <input type="text" name="post[tag][]">
    end

    Sean Doyle

  • Execute the ActionView::Base.field_error_proc within the context of the
    ActionView::Base instance:

    config.action_view.field_error_proc = proc { |html| content_tag(:div, html, class: "field_with_errors") }

    Sean Doyle

  • Add support for button_to ..., authenticity_token: false

    button_to "Create", Post.new, authenticity_token: false
    # => <form class="button_to" method="post" action="/posts"><button type="submit">Create</button></form>
    
    button_to "Create", Post.new, authenticity_token: true
    # => <form class="button_to" method="post" action="/posts"><button type="submit">Create</button><input type="hidden" name="form_token" value="abc123..." autocomplete="off" /></form>
    
    button_to "Create", Post.new, authenticity_token: "secret"
    # => <form class="button_to" method="post" action="/posts"><button type="submit">Create</button><input type="hidden" name="form_token" value="secret" autocomplete="off" /></form>

    Sean Doyle

  • Support rendering <form> elements without [action] attributes by:

    • form_with url: false or form_with ..., html: { action: false }
    • form_for ..., url: false or form_for ..., html: { action: false }
    • form_tag false or form_tag ..., action: false
    • button_to "...", false or button_to(false) { ... }

    Sean Doyle

  • Add :day_format option to date_select

    date_select("article", "written_on", day_format: ->(day) { day.ordinalize })
    # generates day options like <option value="1">1st</option>\n<option value="2">2nd</option>...
    

    Shunichi Ikegami

  • Allow link_to helper to infer link name from Model#to_s when it
    is used with a single argument:

    link_to @profile
    #=> <a href="/profiles/1">Eileen</a>
    

    This assumes the model class implements a to_s method like this:

    class Profile < ApplicationRecord
      # ...
      def to_s
        name
      end
    end
    

    Previously you had to supply a second argument even if the Profile
    model implemented a #to_s method that called the name method.

    link_to @profile, @profile.name
    #=> <a href="/profiles/1">Eileen</a>
    

    Olivier Lacan

  • Support svg unpaired tags for tag helper.

    tag.svg { tag.use('href' => "#cool-icon") }
    # => <svg><use href="#cool-icon"></svg>
    

    Oleksii Vasyliev

  • Improves the performance of ActionView::Helpers::NumberHelper formatters by avoiding the use of
    exceptions as flow control.

    Mike Dalessio

  • preload_link_tag properly inserts as attributes for files with image MIME types, such as JPG or SVG.

    Nate Berkopec

  • Add weekday_options_for_select and weekday_select helper methods. Also adds weekday_select to FormBuilder.

    Drew Bragg, Dana Kashubeck, Kasper Timm Hansen

  • Add caching? helper that returns whether the current code path is being cached and uncacheable! to denote helper methods that can't participate in fragment caching.

    Ben Toews, John Hawthorn, Kasper Timm Hansen, Joel Hawksley

  • Add include_seconds option for time_field.

    <%= form.time_field :foo, include_seconds: false %>
    # => <input value="16:22" type="time" />
    

    Default includes seconds:

    <%= form.time_field :foo %>
    # => <input value="16:22:01.440" type="time" />
    

    This allows you to take advantage of different rendering options in some browsers.

    Alex Ghiculescu

  • Improve error messages when template file does not exist at absolute filepath.

    Ted Whang

  • Add :country_code option to sms_to for consistency with phone_to.

    Jonathan Hefner

  • OpenSSL constants are now used for Digest computations.

    Dirkjan Bussink

  • The translate helper now passes default values that aren't
    translation keys through I18n.translate for interpolation.

    Jonathan Hefner

  • Adds option extname to stylesheet_link_tag to skip default
    .css extension appended to the stylesheet path.

    Before:

    stylesheet_link_tag "style.less"
    # <link href="/stylesheets/style.less.scss" rel="stylesheet">

    After:

    stylesheet_link_tag "style.less", extname: false, skip_pipeline: true, rel: "stylesheet/less"
    # <link href="/stylesheets/style.less" rel="stylesheet/less">

    Abhay Nikam

  • Deprecate render locals to be assigned to instance variables.

    Petrik de Heus

  • Remove legacy default media=screen from stylesheet_link_tag.

    André Luis Leal Cardoso Junior

  • Change ActionView::Helpers::FormBuilder#button to transform formmethod
    attributes into _method="$VERB" Form Data to enable varied same-form actions:

    <%= form_with model: post, method: :put do %>
      <%= form.button "Update" %>
      <%= form.button "Delete", formmethod: :delete %>
    <% end %>
    <%# => <form action="posts/1">
        =>   <input type="hidden" name="_method" value="put">
        =>   <button type="submit">Update</button>
        =>   <button type="submit" formmethod="post" name="_method" value="delete">Delete</button>
        => </form>
    %>
    

    Sean Doyle

  • Change ActionView::Helpers::UrlHelper#button_to to always render a
    <button> element, regardless of whether or not the content is passed as
    the first argument or as a block.

    <%= button_to "Delete", post_path(@post), method: :delete %>
    # => <form action="/posts/1"><input type="hidden" name="_method" value="delete"><button type="submit">Delete</button></form>
    
    <%= button_to post_path(@post), method: :delete do %>
      Delete
    <% end %>
    # => <form action="/posts/1"><input type="hidden" name="_method" value="delete"><button type="submit">Delete</button></form>
    

    Sean Doyle, Dusan Orlovic

  • Add config.action_view.preload_links_header to allow disabling of
    the Link header being added by default when using stylesheet_link_tag
    and javascript_include_tag.

    Andrew White

  • The translate helper now resolves default values when a nil key is
    specified, instead of always returning nil.

    Jonathan Hefner

  • Add config.action_view.image_loading to configure the default value of
    the image_tag :loading option.

    By setting config.action_view.image_loading = "lazy", an application can opt in to
    lazy loading images sitewide, without changing view code.

    Jonathan Hefner

  • ActionView::Helpers::FormBuilder#id returns the value
    of the <form> element's id attribute. With a method argument, returns
    the id attribute for a form field with that name.

    <%= form_for @post do |f| %>
      <%# ... %>
    
      <% content_for :sticky_footer do %>
        <%= form.button(form: f.id) %>
      <% end %>
    <% end %>
    

    Sean Doyle

  • ActionView::Helpers::FormBuilder#field_id returns the value generated by
    the FormBuilder for the given attribute name.

    <%= form_for @post do |f| %>
      <%= f.label :title %>
      <%= f.text_field :title, aria: { describedby: f.field_id(:title, :error) } %>
      <%= tag.span("is blank", id: f.field_id(:title, :error) %>
    <% end %>
    

    Sean Doyle

  • Add tag.attributes to transform a Hash into HTML Attributes, ready to be
    interpolated into ERB.

    <input <%= tag.attributes(type: :text, aria: { label: "Search" }) %> >
    # => <input type="text" aria-label="Search">
    

    Sean Doyle

Active Job

  • Remove deprecated :return_false_on_aborted_enqueue option.

    Rafael Mendonça França

  • Deprecated Rails.config.active_job.skip_after_callbacks_if_terminated.

    Rafael Mendonça França

  • Removed deprecated behavior that was not halting after_enqueue/after_perform callbacks when a
    previous callback was halted with throw :abort.

    Rafael Mendonça França

  • Raise an SerializationError in Serializer::ModuleSerializer
    if the module name is not present.

    Veerpal Brar

  • Allow a job to retry indefinitely

    The attempts parameter of the retry_on method now accepts the
    symbol reference :unlimited in addition to a specific number of retry
    attempts to allow a developer to specify that a job should retry
    forever until it succeeds.

    class MyJob < ActiveJob::Base
      retry_on(AlwaysRetryException, attempts: :unlimited)
    
      # the actual job code
    end
    

    Daniel Morton

  • Added possibility to check on :priority in test helper methods
    assert_enqueued_with and assert_performed_with.

    Wojciech Wnętrzak

  • OpenSSL constants are now used for Digest computations.

    Dirkjan Bussink

  • Add a Serializer for the Range class.

    This should allow things like MyJob.perform_later(range: 1..100).

  • Communicate enqueue failures to callers of perform_later.

    perform_later can now optionally take a block which will execute after
    the adapter attempts to enqueue the job. The block will receive the job
    instance as an argument even if the enqueue was not successful.
    Additionally, ActiveJob adapters now have the ability to raise an
    ActiveJob::EnqueueError which will be caught and stored in the job
    instance so code attempting to enqueue jobs can inspect any raised
    EnqueueError using the block.

    MyJob.perform_later do |job|
      unless job.successfully_enqueued?
        if job.enqueue_error&.message == "Redis was unavailable"
          # invoke some code that will retry the job after a delay
        end
      end
    end
    

    Daniel Morton

  • Don't log rescuable exceptions defined with rescue_from.

    Hu Hailin

  • Allow rescue_from to rescue all exceptions.

    Adrianna Chang, Étienne Barrié

Active Model

  • Remove support to Marshal load Rails 5.x ActiveModel::AttributeSet format.

    Rafael Mendonça França

  • Remove support to Marshal and YAML load Rails 5.x error format.

    Rafael Mendonça França

  • Remove deprecated support to use []= in ActiveModel::Errors#messages.

    Rafael Mendonça França

  • Remove deprecated support to delete errors from ActiveModel::Errors#messages.

    Rafael Mendonça França

  • Remove deprecated support to clear errors from ActiveModel::Errors#messages.

    Rafael Mendonça França

  • Remove deprecated support concat errors to ActiveModel::Errors#messages.

    Rafael Mendonça França

  • Remove deprecated ActiveModel::Errors#to_xml.

    Rafael Mendonça França

  • Remove deprecated ActiveModel::Errors#keys.

    Rafael Mendonça França

  • Remove deprecated ActiveModel::Errors#values.

    Rafael Mendonça França

  • Remove deprecated ActiveModel::Errors#slice!.

    Rafael Mendonça França

  • Remove deprecated ActiveModel::Errors#to_h.

    Rafael Mendonça França

  • Remove deprecated enumeration of ActiveModel::Errors instances as a Hash.

    Rafael Mendonça França

  • Clear secure password cache if password is set to nil

    Before:

    user.password = 'something'
    user.password = nil

    user.password # => 'something'

    Now:

    user.password = 'something'
    user.password = nil

    user.password # => nil

    Markus Doits

  • Introduce ActiveModel::API.

    Make ActiveModel::API the minimum API to talk with Action Pack and Action View.
    This will allow adding more functionality to ActiveModel::Model.

    Petrik de Heus, Nathaniel Watts

  • Fix dirty check for Float::NaN and BigDecimal::NaN.

    Float::NaN and BigDecimal::NaN in Ruby are special values
    and can't be compared with ==.

    Marcelo Lauxen

  • Fix to_json for ActiveModel::Dirty object.

    Exclude mutations_from_database attribute from json as it lead to recursion.

    Anil Maurya

  • Add ActiveModel::AttributeSet#values_for_database.

    Returns attributes with values for assignment to the database.

    Chris Salzberg

  • Fix delegation in ActiveModel::Type::Registry#lookup and ActiveModel::Type.lookup.

    Passing a last positional argument {} would be incorrectly considered as keyword argument.

    Benoit Daloze

  • Cache and re-use generated attribute methods.

    Generated methods with identical implementations will now share their instruction sequences
    leading to reduced memory retention, and slightly faster load time.

    Jean Boussier

  • Add in: range parameter to numericality validator.

    Michal Papis

  • Add locale argument to ActiveModel::Name#initialize to be used to generate the singular,
    plural, route_key and singular_route_key values.

    Lukas Pokorny

  • Make ActiveModel::Errors#inspect slimmer for readability

    lulalala

Active Record

  • Better handle SQL queries with invalid encoding.

    Post.create(name: "broken \xC8 UTF-8")

    Would cause all adapters to fail in a non controlled way in the code
    responsible to detect write queries.

    The query is now properly passed to the database connection, which might or might
    not be able to handle it, but will either succeed or failed in a more correct way.

    Jean Boussier

  • Move database and shard selection config options to a generator.

    Rather than generating the config options in production.rb when applications are created, applications can now run a generator to create an initializer and uncomment / update options as needed. All multi-db configuration can be implemented in this initializer.

    Eileen M. Uchitelle

  • Remove deprecated ActiveRecord::DatabaseConfigurations::DatabaseConfig#spec_name.

    Rafael Mendonça França

  • Remove deprecated ActiveRecord::Connection#in_clause_length.

    Rafael Mendonça França

  • Remove deprecated ActiveRecord::Connection#allowed_index_name_length.

    Rafael Mendonça França

  • Remove deprecated ActiveRecord::Base#remove_connection.

    Rafael Mendonça França

  • Load STI Models in fixtures

    Data from Fixtures now loads based on the specific class for models with
    Single Table Inheritance. This affects enums defined in subclasses, previously
    the value of these fields was not parsed and remained nil

    Andres Howard

  • #authenticate returns false when the password is blank instead of raising an error.

    Muhammad Muhammad Ibrahim

  • Fix ActiveRecord::QueryMethods#in_order_of behavior for integer enums.

    ActiveRecord::QueryMethods#in_order_of didn't work as expected for enums stored as integers in the database when passing an array of strings or symbols as the order argument. This unexpected behavior occurred because the string or symbol values were not casted to match the integers in the database.

    The following example now works as expected:

    class Book < ApplicationRecord
      enum status: [:proposed, :written, :published]
    end
    
    Book.in_order_of(:status, %w[written published proposed])

    Alexandre Ruban

  • Ignore persisted in-memory records when merging target lists.

    Kevin Sjöberg

  • Add a new option :update_only to upsert_all to configure the list of columns to update in case of conflict.

    Before, you could only customize the update SQL sentence via :on_duplicate. There is now a new option :update_only that lets you provide a list of columns to update in case of conflict:

    Commodity.upsert_all(
      [
        { id: 2, name: "Copper", price: 4.84 },
        { id: 4, name: "Gold", price: 1380.87 },
        { id: 6, name: "Aluminium", price: 0.35 }
      ],
      update_only: [:price] # Only prices will be updated
    )

    Jorge Manrubia

  • Remove deprecated ActiveRecord::Result#map! and ActiveRecord::Result#collect!.

    Rafael Mendonça França

  • Remove deprecated ActiveRecord::Base.configurations.to_h.

    Rafael Mendonça França

  • Remove deprecated ActiveRecord::Base.configurations.default_hash.

    Rafael Mendonça França

  • Remove deprecated ActiveRecord::Base.arel_attribute.

    Rafael Mendonça França

  • Remove deprecated ActiveRecord::Base.connection_config.

    Rafael Mendonça França

  • Filter attributes in SQL logs

    Previously, SQL queries in logs containing ActiveRecord::Base.filter_attributes were not filtered.

    Now, the filter attributes will be masked [FILTERED] in the logs when prepared_statement is enabled.

    # Before:
      Foo Load (0.2ms)  SELECT "foos".* FROM "foos" WHERE "foos"."passw" = ? LIMIT ?  [["passw", "hello"], ["LIMIT", 1]]
    
    # After:
      Foo Load (0.5ms)  SELECT "foos".* FROM "foos" WHERE "foos"."passw" = ? LIMIT ?  [["passw", "[FILTERED]"], ["LIMIT", 1]]
    

    Aishwarya Subramanian

  • Remove deprecated Tasks::DatabaseTasks.spec.

    Rafael Mendonça França

  • Remove deprecated Tasks::DatabaseTasks.current_config.

    Rafael Mendonça França

  • Deprecate Tasks::DatabaseTasks.schema_file_type.

    Rafael Mendonça França

  • Remove deprecated Tasks::DatabaseTasks.dump_filename.

    Rafael Mendonça França

  • Remove deprecated Tasks::DatabaseTasks.schema_file.

    Rafael Mendonça França

  • Remove deprecated environment and name arguments from Tasks::DatabaseTasks.schema_up_to_date?.

    Rafael Mendonça França

  • Merging conditions on the same column no longer maintain both conditions,
    and will be consistently replaced by the latter condition.

    # Rails 6.1 (IN clause is replaced by merger side equality condition)
    Author.where(id: [david.id, mary.id]).merge(Author.where(id: bob)) # => [bob]
    # Rails 6.1 (both conflict conditions exists, deprecated)
    Author.where(id: david.id..mary.id).merge(Author.where(id: bob)) # => []
    # Rails 6.1 with rewhere to migrate to Rails 7.0's behavior
    Author.where(id: david.id..mary.id).merge(Author.where(id: bob), rewhere: true) # => [bob]
    # Rails 7.0 (same behavior with IN clause, mergee side condition is consistently replaced)
    Author.where(id: [david.id, mary.id]).merge(Author.where(id: bob)) # => [bob]
    Author.where(id: david.id..mary.id).merge(Author.where(id: bob)) # => [bob]
    
    *Rafael Mendonça França*
  • Remove deprecated support to Model.reorder(nil).first to search using non-deterministic order.

    Rafael Mendonça França

  • Remove deprecated rake tasks:

    • db:schema:load_if_ruby
    • db:structure:dump
    • db:structure:load
    • db:structure:load_if_sql
    • db:structure:dump:#{name}
    • db:structure:load:#{name}
    • db:test:load_structure
    • db:test:load_structure:#{name}

    Rafael Mendonça França

  • Remove deprecated DatabaseConfig#config method.

    Rafael Mendonça França

  • Rollback transactions when the block returns earlier than expected.

    Before this change, when a transaction block returned early, the transaction would be committed.

    The problem is that timeouts triggered inside the transaction block was also making the incomplete transaction
    to be committed, so in order to avoid this mistake, the transaction block is rolled back.

    Rafael Mendonça França

  • Add middleware for automatic shard swapping.

    Provides a basic middleware to perform automatic shard swapping. Applications will provide a resolver which will determine for an individual request which shard should be used. Example:

    config.active_record.shard_resolver = ->(request) {
      subdomain = request.subdomain
      tenant = Tenant.find_by_subdomain!(subdomain)
      tenant.shard
    }

    See guides for more details.

    Eileen M. Uchitelle, John Crepezzi

  • Remove deprecated support to pass a column to type_cast.

    Rafael Mendonça França

  • Remove deprecated support to type cast to database values ActiveRecord::Base objects.

    Rafael Mendonça França

  • Remove deprecated support to quote ActiveRecord::Base objects.

    Rafael Mendonça França

  • Remove deprecacated support to resolve connection using "primary" as connection specification name.

    Rafael Mendonça França

  • Remove deprecation warning when using :interval column is used in PostgreSQL database.

    Now, interval columns will return ActiveSupport::Duration objects instead of strings.

    To keep the old behavior, you can add this line to your model:

    attribute :column, :string

    Rafael Mendonça França

  • Remove deprecated support to YAML load ActiveRecord::Base instance in the Rails 4.2 and 4.1 formats.

    Rafael Mendonça França

  • Remove deprecated option :spec_name in the configs_for method.

    Rafael Mendonça França

  • Remove deprecated ActiveRecord::Base.allow_unsafe_raw_sql.

    Rafael Mendonça França

  • Fix regression bug that caused ignoring additional conditions for preloading has_many-through relations.

    Fixes #43132

    Alexander Pauly

  • Fix has_many inversing recursion on models with recursive associations.

    Gannon McGibbon

  • Add accepts_nested_attributes_for support for delegated_type

    class Entry < ApplicationRecord
      delegated_type :entryable, types: %w[ Message Comment ]
      accepts_nested_attributes_for :entryable
    end
    
    entry = Entry.create(entryable_type: 'Message', entryable_attributes: { content: 'Hello world' })
    # => #<Entry:0x00>
    # id: 1
    # entryable_id: 1,
    # entryable_type: 'Message'
    # ...>
    
    entry.entryable
    # => #<Message:0x01>
    # id: 1
    # content: 'Hello world'
    # ...>

    Previously it would raise an error:

    Entry.create(entryable_type: 'Message', entryable_attributes: { content: 'Hello world' })
    # ArgumentError: Cannot build association `entryable'. Are you trying to build a polymorphic one-to-one association?

    Sjors Baltus

  • Use subquery for DELETE with GROUP_BY and HAVING clauses.

    Prior to this change, deletes with GROUP_BY and HAVING were returning an error.

    After this change, GROUP_BY and HAVING are valid clauses in DELETE queries, generating the following query:

    DELETE FROM "posts" WHERE "posts"."id" IN (
        SELECT "posts"."id" FROM "posts" INNER JOIN "comments" ON "comments"."post_id" = "posts"."id" GROUP BY "posts"."id" HAVING (count(comments.id) >= 2))
    )  [["flagged", "t"]]

    Ignacio Chiazzo Cardarello

  • Use subquery for UPDATE with GROUP_BY and HAVING clauses.

    Prior to this change, updates with GROUP_BY and HAVING were being ignored, generating a SQL like this:

    UPDATE "posts" SET "flagged" = ? WHERE "posts"."id" IN (
        SELECT "posts"."id" FROM "posts" INNER JOIN "comments" ON "comments"."post_id" = "posts"."id"
    )  [["flagged", "t"]]

    After this change, GROUP_BY and HAVING clauses are used as a subquery in updates, like this:

    UPDATE "posts" SET "flagged" = ? WHERE "posts"."id" IN (
        SELECT "posts"."id" FROM "posts" INNER JOIN "comments" ON "comments"."post_id" = "posts"."id"
        GROUP BY posts.id HAVING (count(comments.id) >= 2)
    )  [["flagged", "t"]]

    Ignacio Chiazzo Cardarello

  • Add support for setting the filename of the schema or structure dump in the database config.

    Applications may now set their the filename or path of the schema / structure dump file in their database configuration.

    production:
      primary:
        database: my_db
        schema_dump: my_schema_dump_filename.rb
      animals:
        database: animals_db
        schema_dump: false

    The filename set in schema_dump will be used by the application. If set to false the schema will not be dumped. The database tasks are responsible for adding the database directory to the filename. If a full path is provided, the Rails tasks will use that instead of ActiveRecord::DatabaseTasks.db_dir.

    Eileen M. Uchitelle, Ryan Kerr

  • Add ActiveRecord::Base.prohibit_shard_swapping to prevent attempts to change the shard within a block.

    John Crepezzi, Eileen M. Uchitelle

  • Filter unchanged attributes with default function from insert query when partial_inserts is disabled.

    Akshay Birajdar, Jacopo Beschi

  • Add support for FILTER clause (SQL:2003) to Arel.

    Currently supported by PostgreSQL 9.4+ and SQLite 3.30+.

    Andrey Novikov

  • Automatically set timestamps on record creation during bulk insert/upsert

    Prior to this change, only updates during an upsert operation (e.g. upsert_all) would touch timestamps (updated_{at,on}). Now, record creations also touch timestamp columns ({created,updated}_{at,on}).

    This behaviour is controlled by the <model>.record_timestamps config, matching the behaviour of create, update, etc. It can also be overridden by using the record_timestamps: keyword argument.

    Note that this means upsert_all on models with record_timestamps = false will no longer touch updated_{at,on} automatically.

    Sam Bostock

  • Don't require role when passing shard to connected_to.

    connected_to can now be called with a shard only. Note that role is still inherited if connected_to calls are nested.

    Eileen M. Uchitelle

  • Add option to lazily load the schema cache on the connection.

    Previously, the only way to load the schema cache in Active Record was through the Railtie on boot. This option provides the ability to load the schema cache on the connection after it's been established. Loading the cache lazily on the connection can be beneficial for Rails applications that use multiple databases because it will load the cache at the time the connection is established. Currently Railties doesn't have access to the connections before boot.

    To use the cache, set config.active_record.lazily_load_schema_cache = true in your application configuration. In addition a schema_cache_path should be set in your database configuration if you don't want to use the default "db/schema_cache.yml" path.

    Eileen M. Uchitelle

  • Allow automatic inverse_of detection for associations with scopes.

    Automatic inverse_of detection now works for associations with scopes. For
    example, the comments association here now automatically detects
    inverse_of: :post, so we don't need to pass that option:

    class Post < ActiveRecord::Base
      has_many :comments, -> { visible }
    end
    
    class Comment < ActiveRecord::Base
      belongs_to :post
    end

    Note that the automatic detection still won't work if the inverse
    association has a scope. In this example a scope on the post association
    would still prevent Rails from finding the inverse for the comments
    association.

    This will be the default for new apps in Rails 7. To opt in:

    config.active_record.automatic_scope_inversing = true

    Daniel Colson, Chris Bloom

  • Accept optional transaction args to ActiveRecord::Locking::Pessimistic#with_lock

    #with_lock now accepts transaction options like requires_new:,
    isolation:, and joinable:

    John Mileham

  • Adds support for deferrable foreign key constraints in PostgreSQL.

    By default, foreign key constraints in PostgreSQL are checked after each statement. This works for most use cases,
    but becomes a major limitation when creating related records before the parent record is inserted into the database.
    One example of this is looking up / creating a person via one or more unique alias.

    Person.transaction do
      alias = Alias
        .create_with(user_id: SecureRandom.uuid)
        .create_or_find_by(name: "DHH")
    
      person = Person
        .create_with(name: "David Heinemeier Hansson")
        .create_or_find_by(id: alias.user_id)
    end

    Using the default behavior, the transaction would fail when executing the first INSERT statement.

    By passing the :deferrable option to the add_foreign_key statement in migrations, it's possible to defer this
    check.

    add_foreign_key :aliases, :person, deferrable: true

    Passing deferrable: true doesn't change the default behavior, but allows manually deferring the check using
    SET CONSTRAINTS ALL DEFERRED within a transaction. This will cause the foreign keys to be checked after the
    transaction.

    It's also possible to adjust the default behavior from an immediate check (after the statement), to a deferred check
    (after the transaction):

    add_foreign_key :aliases, :person, deferrable: :deferred

    Benedikt Deicke

  • Allow configuring Postgres password through the socket URL.

    For example:

    ActiveRecord::DatabaseConfigurations::UrlConfig.new(
      :production, :production, 'postgres:///?user=user&password=secret&dbname=app', {}
    ).configuration_hash

    will now return,

    { :user=>"user", :password=>"secret", :dbname=>"app", :adapter=>"postgresql" }

    Abeid Ahmed

  • PostgreSQL: support custom enum types

    In migrations, use create_enum to add a new enum type, and t.enum to add a column.

    def up
      create_enum :mood, ["happy", "sad"]
    
      change_table :cats do |t|
        t.enum :current_mood, enum_type: "mood", default: "happy", null: false
      end
    end

    Enums will be presented correctly in schema.rb. Note that this is only supported by
    the PostgreSQL adapter.

    Alex Ghiculescu

  • Avoid COMMENT statements in PostgreSQL structure dumps

    COMMENT statements are now omitted from the output of db:structure:dump when using PostgreSQL >= 11.
    This allows loading the dump without a pgsql superuser account.

    Fixes #36816, #43107.

    Janosch Müller

  • Add support for generated columns in PostgreSQL adapter

    Generated columns are supported since version 12.0 of PostgreSQL. This adds
    support of those to the PostgreSQL adapter.

    create_table :users do |t|
      t.string :name
      t.virtual :name_upcased, type: :string, as: 'upper(name)', stored: true
    end

    Michał Begejowicz

  • Remove warning when overwriting existing scopes

    Removes the following unnecessary warning message that appeared when overwriting existing scopes

    Creating scope :my_scope_name. Overwriting existing method "MyClass.my_scope_name" when overwriting existing scopes
    

    Weston Ganger

  • Use full precision for updated_at in insert_all/upsert_all

    CURRENT_TIMESTAMP provides differing precision depending on the database,
    and not all databases support explicitly specifying additional precision.

    Instead, we delegate to the new connection.high_precision_current_timestamp
    for the SQL to produce a high precision timestamp on the current database.

    Fixes #42992

    Sam Bostock

  • Add ssl support for postgresql database tasks

    Add PGSSLMODE, PGSSLCERT, PGSSLKEY and PGSSLROOTCERT to pg_env from database config
    when running postgresql database tasks.

    # config/database.yml
    
    production:
      sslmode: verify-full
      sslcert: client.crt
      sslkey: client.key
      sslrootcert: ca.crt

    Environment variables

    PGSSLMODE=verify-full
    PGSSLCERT=client.crt
    PGSSLKEY=client.key
    PGSSLROOTCERT=ca.crt
    

    Fixes #42994

    Michael Bayucot

  • Avoid scoping update callbacks in ActiveRecord::Relation#update!.

    Making it consistent with how scoping is applied only to the query in ActiveRecord::Relation#update
    and not also to the callbacks from the update itself.

    Dylan Thacker-Smith

  • Fix 2 cases that inferred polymorphic class from the association's foreign_type
    using String#constantize instead of the model's polymorphic_class_for.

    When updating a polymorphic association, the old foreign_type was not inferred correctly when:

    1. touching the previously associated record
    2. updating the previously associated record's counter_cache

    Jimmy Bourassa

  • Add config option for ignoring tables when dumping the schema cache.

    Applications can now be configured to ignore certain tables when dumping the schema cache.

    The configuration option can table an array of tables:

    config.active_record.schema_cache_ignored_tables = ["ignored_table", "another_ignored_table"]

    Or a regex:

    config.active_record.schema_cache_ignored_tables = [/^_/]

    Eileen M. Uchitelle

  • Make schema cache methods return consistent results.

    Previously the schema cache methods primary_keys, columns, columns_hash, and indexes
    would behave differently than one another when a table didn't exist and differently across
    database adapters. This change unifies the behavior so each method behaves the same regardless
    of adapter.

    The behavior now is:

    columns: (unchanged) raises a db error if the table does not exist.
    columns_hash: (unchanged) raises a db error if the table does not exist.
    primary_keys: (unchanged) returns nil if the table does not exist.
    indexes: (changed for mysql2) returns [] if the table does not exist.

    Eileen M. Uchitelle

  • Reestablish connection to previous database after after running db:schema:load:name

    After running db:schema:load:name the previous connection is restored.

    Jacopo Beschi

  • Add database config option database_tasks

    If you would like to connect to an external database without any database
    management tasks such as schema management, migrations, seeds, etc. you can set
    the per database config option database_tasks: false

    # config/database.yml
    
    production:
      primary:
        database: my_database
        adapter: mysql2
      animals:
        database: my_animals_database
        adapter: mysql2
        database_tasks: false

    Weston Ganger

  • Fix ActiveRecord::InternalMetadata to not be broken by config.active_record.record_timestamps = false

    Since the model always create the timestamp columns, it has to set them, otherwise it breaks
    various DB management tasks.

    Fixes #42983

  • Add ActiveRecord::QueryLogs.

    Configurable tags can be automatically added to all SQL queries generated by Active Record.

    # config/application.rb
    module MyApp
      class Application < Rails::Application
        config.active_record.query_log_tags_enabled = true
      end
    end

    By default the application, controller and action details are added to the query tags:

    class BooksController < ApplicationController
      def index
        @books = Book.all
      end
    end
    GET /books
    # SELECT * FROM books /*application:MyApp;controller:books;action:index*/

    Custom tags containing static values and Procs can be defined in the application configuration:

    config.active_record.query_log_tags = [
      :application,
      :controller,
      :action,
      {
        custom_static: "foo",
        custom_dynamic: -> { Time.now }
      }
    ]

    Keeran Raj Hawoldar, Eileen M. Uchitelle, Kasper Timm Hansen

  • Added support for multiple databases to rails db:setup and rails db:reset.

    Ryan Hall

  • Add ActiveRecord::Relation#structurally_compatible?.

    Adds a query method by which a user can tell if the relation that they're
    about to use for #or or #and is structurally compatible with the
    receiver.

    Kevin Newton

  • Add ActiveRecord::QueryMethods#in_order_of.

    This allows you to specify an explicit order that you'd like records
    returned in based on a SQL expression. By default, this will be accomplished
    using a case statement, as in:

    Post.in_order_of(:id, [3, 5, 1])

    will generate the SQL:

    SELECT "posts".* FROM "posts" ORDER BY CASE "posts"."id" WHEN 3 THEN 1 WHEN 5 THEN 2 WHEN 1 THEN 3 ELSE 4 END ASC

    However, because this functionality is built into MySQL in the form of the
    FIELD function, that connection adapter will generate the following SQL
    instead:

    SELECT "posts".* FROM "posts" ORDER BY FIELD("posts"."id", 1, 5, 3) DESC

    Kevin Newton

  • Fix eager_loading? when ordering with Symbol.

    eager_loading? is triggered correctly when using order with symbols.

    scope = Post.includes(:comments).order(:"comments.label")
    => true

    Jacopo Beschi

  • Two change tracking methods are added for belongs_to associations.

    The association_changed? method (assuming an association named :association) returns true
    if a different associated object has been assigned and the foreign key will be updated in the
    next save.

    The association_previously_changed? method returns true if the previous save updated the
    association to reference a different associated object.

    George Claghorn

  • Add option to disable schema dump per-database.

    Dumping the schema is on by default for all databases in an application. To turn it off for a
    specific database, use the schema_dump option:

    # config/database.yml
    
    production:
      schema_dump: false

    Luis Vasconcellos, Eileen M. Uchitelle

  • Fix eager_loading? when ordering with Hash syntax.

    eager_loading? is triggered correctly when using order with hash syntax
    on an outer table.

    Post.includes(:comments).order({ "comments.label": :ASC }).eager_loading?
    # => true

    Jacopo Beschi

  • Move the forcing of clear text encoding to the ActiveRecord::Encryption::Encryptor.

    Fixes #42699.

    J Smith

  • partial_inserts is now disabled by default in new apps.

    This will be the default for new apps in Rails 7. To opt in:

    config.active_record.partial_inserts = true

    If a migration removes the default value of a column, this option
    would cause old processes to no longer be able to create new records.

    If you need to remove a column, you should first use ignored_columns
    to stop using it.

    Jean Boussier

  • Rails can now verify foreign keys after loading fixtures in tests.

    This will be the default for new apps in Rails 7. To opt in:

    config.active_record.verify_foreign_keys_for_fixtures = true

    Tests will not run if there is a foreign key constraint violation in your fixture data.

    The feature is supported by SQLite and PostgreSQL, other adapters can also add support for it.

    Alex Ghiculescu

  • Clear cached has_one association after setting belongs_to association to nil.

    After setting a belongs_to relation to nil and updating an unrelated attribute on the owner,
    the owner should still return nil on the has_one relation.

    Fixes #42597.

    Michiel de Mare

  • OpenSSL constants are now used for Digest computations.

    Dirkjan Bussink

  • Adds support for if_not_exists to add_foreign_key and if_exists to remove_foreign_key.

    Applications can set their migrations to ignore exceptions raised when adding a foreign key
    that already exists or when removing a foreign key that does not exist.

    Example Usage:

    class AddAuthorsForeignKeyToArticles < ActiveRecord::Migration[7.0]
      def change
        add_foreign_key :articles, :authors, if_not_exists: true
      end
    end
    class RemoveAuthorsForeignKeyFromArticles < ActiveRecord::Migration[7.0]
      def change
        remove_foreign_key :articles, :authors, if_exists: true
      end
    end

    Roberto Miranda

  • Prevent polluting ENV during postgresql structure dump/load.

    Some configuration parameters were provided to pg_dump / psql via
    environment variables which persisted beyond the command being run, and may
    have caused subsequent commands and connections to fail. Tasks running
    across multiple postgresql databases like rails db:test:prepare may have
    been affected.

    Samuel Cochran

  • Set precision 6 by default for datetime columns.

    By default, datetime columns will have microseconds precision instead of seconds precision.

    Roberto Miranda

  • Allow preloading of associations with instance dependent scopes.

    John Hawthorn, John Crepezzi, Adam Hess, Eileen M. Uchitelle, Dinah Shi

  • Do not try to rollback transactions that failed due to a ActiveRecord::TransactionRollbackError.

    Jamie McCarthy

  • Active Record Encryption will now encode values as UTF-8 when using deterministic
    encryption. The encoding is part of the encrypted payload, so different encodings for
    different values result in different ciphertexts. This can break unique constraints and
    queries.

    The new behavior is configurable via active_record.encryption.forced_encoding_for_deterministic_encryption
    that is Encoding::UTF_8 by default. It can be disabled by setting it to nil.

    Jorge Manrubia

  • The MySQL adapter now cast numbers and booleans bind parameters to string for safety reasons.

    When comparing a string and a number in a query, MySQL converts the string to a number. So for
    instance "foo" = 0, will implicitly cast "foo" to 0 and will evaluate to TRUE which can
    lead to security vulnerabilities.

    Active Record already protect against that vulnerability when it knows the type of the column
    being compared, however until now it was still vulnerable when using bind parameters:

    User.where("login_token = ?", 0).first

    Would perform:

    SELECT * FROM `users` WHERE `login_token` = 0 LIMIT 1;

    Now it will perform:

    SELECT * FROM `users` WHERE `login_token` = '0' LIMIT 1;

    Jean Boussier

  • Fixture configurations (_fixture) are now strictly validated.

    If an error will be raised if that entry contains unknown keys while previously it
    would silently have no effects.

    Jean Boussier

  • Add ActiveRecord::Base.update! that works like ActiveRecord::Base.update but raises exceptions.

    This allows for the same behavior as the instance method #update! at a class level.

    Person.update!(:all, state: "confirmed")

    Dorian Marié

  • Add ActiveRecord::Base#attributes_for_database.

    Returns attributes with values for assignment to the database.

    Chris Salzberg

  • Use an empty query to check if the PostgreSQL connection is still active.

    An empty query is faster than SELECT 1.

    Heinrich Lee Yu

  • Add ActiveRecord::Base#previously_persisted?.

    Returns true if the object has been previously persisted but now it has been deleted.

  • Deprecate partial_writes in favor of partial_inserts and partial_updates.

    This allows to have a different behavior on update and create.

    Jean Boussier

  • Fix compatibility with psych >= 4.

    Starting in Psych 4.0.0 YAML.load behaves like YAML.safe_load. To preserve compatibility,
    Active Record's schema cache loader and YAMLColumn now uses YAML.unsafe_load if available.

    Jean Boussier

  • ActiveRecord::Base.logger is now a class_attribute.

    This means it can no longer be accessed directly through @@logger, and that setting logger =
    on a subclass won't change the parent's logger.

    Jean Boussier

  • Add .asc.nulls_first for all databases. Unfortunately MySQL still doesn't like nulls_last.

    Keenan Brock

  • Improve performance of one? and many? by limiting the generated count query to 2 results.

    Gonzalo Riestra

  • Don't check type when using if_not_exists on add_column.

    Previously, if a migration called add_column with the if_not_exists option set to true
    the column_exists? check would look for a column with the same name and type as the migration.

    Recently it was discovered that the type passed to the migration is not always the same type
    as the column after migration. For example a column set to :mediumblob in the migration will
    be casted to binary when calling column.type. Since there is no straightforward way to cast
    the type to the database type without running the migration, we opted to drop the type check from
    add_column. This means that migrations adding a duplicate column with a different type will no
    longer raise an error.

    Eileen M. Uchitelle

  • Log a warning message when running SQLite in production.

    Using SQLite in production ENV is generally discouraged. SQLite is also the default adapter
    in a new Rails application.
    For the above reasons log a warning message when running SQLite in production.

    The warning can be disabled by setting config.active_record.sqlite3_production_warning=false.

    Jacopo Beschi

  • Add option to disable joins for has_one associations.

    In a multiple database application, associations can't join across
    databases. When set, this option instructs Rails to generate 2 or
    more queries rather than generating joins for has_one associations.

    Set the option on a has one through association:

    class Person
      has_one :dog
      has_one :veterinarian, through: :dog, disable_joins: true
    end

    Then instead of generating join SQL, two queries are used for @person.veterinarian:

    SELECT "dogs"."id" FROM "dogs" WHERE "dogs"."person_id" = ?  [["person_id", 1]]
    SELECT "veterinarians".* FROM "veterinarians" WHERE "veterinarians"."dog_id" = ?  [["dog_id", 1]]
    

    Sarah Vessels, Eileen M. Uchitelle

  • Arel::Visitors::Dot now renders a complete set of properties when visiting
    Arel::Nodes::SelectCore, SelectStatement, InsertStatement, UpdateStatement, and
    DeleteStatement, which fixes #42026. Previously, some properties were omitted.

    Mike Dalessio

  • Arel::Visitors::Dot now supports Arel::Nodes::Bin, Case, CurrentRow, Distinct,
    DistinctOn, Else, Except, InfixOperation, Intersect, Lock, NotRegexp, Quoted,
    Regexp, UnaryOperation, Union, UnionAll, When, and With. Previously, these node
    types caused an exception to be raised by Arel::Visitors::Dot#accept.

    Mike Dalessio

  • Optimize remove_columns to use a single SQL statement.

    remove_columns :my_table, :col_one, :col_two

    Now results in the following SQL:

    ALTER TABLE "my_table" DROP COLUMN "col_one", DROP COLUMN "col_two"

    Jon Dufresne

  • Ensure has_one autosave association callbacks get called once.

    Change the has_one autosave callback to be non cyclic as well.
    By doing this the autosave callback are made more consistent for
    all 3 cases: has_many, has_one, and belongs_to.

    Petrik de Heus

  • Add option to disable joins for associations.

    In a multiple database application, associations can't join across
    databases. When set, this option instructs Rails to generate 2 or
    more queries rather than generating joins for associations.

    Set the option on a has many through association:

    class Dog
      has_many :treats, through: :humans, disable_joins: true
      has_many :humans
    end

    Then instead of generating join SQL, two queries are used for @dog.treats:

    SELECT "humans"."id" FROM "humans" WHERE "humans"."dog_id" = ?  [["dog_id", 1]]
    SELECT "treats".* FROM "treats" WHERE "treats"."human_id" IN (?, ?, ?)  [["human_id", 1], ["human_id", 2], ["human_id", 3]]
    

    Eileen M. Uchitelle, Aaron Patterson, Lee Quarella

  • Add setting for enumerating column names in SELECT statements.

    Adding a column to a PostgreSQL database, for example, while the application is running can
    change the result of wildcard SELECT * queries, which invalidates the result
    of cached prepared statements and raises a PreparedStatementCacheExpired error.

    When enabled, Active Record will avoid wildcards and always include column names
    in SELECT queries, which will return consistent results and avoid prepared
    statement errors.

    Before:

    Book.limit(5)
    # SELECT * FROM books LIMIT 5

    After:

    # config/application.rb
    module MyApp
      class Application < Rails::Application
        config.active_record.enumerate_columns_in_select_statements = true
      end
    end
    
    # or, configure per-model
    class Book < ApplicationRecord
      self.enumerate_columns_in_select_statements = true
    end
    Book.limit(5)
    # SELECT id, author_id, name, format, status, language, etc FROM books LIMIT 5

    Matt Duszynski

  • Allow passing SQL as on_duplicate value to #upsert_all to make it possible to use raw SQL to update columns on conflict:

    Book.upsert_all(
      [{ id: 1, status: 1 }, { id: 2, status: 1 }],
      on_duplicate: Arel.sql("status = GREATEST(books.status, EXCLUDED.status)")
    )

    Vladimir Dementyev

  • Allow passing SQL as returning statement to #upsert_all:

    Article.insert_all(
      [
        { title: "Article 1", slug: "article-1", published: false },
        { title: "Article 2", slug: "article-2", published: false }
      ],
      returning: Arel.sql("id, (xmax = '0') as inserted, name as new_name")
    )

    Vladimir Dementyev

  • Deprecate legacy_connection_handling.

    Eileen M. Uchitelle

  • Add attribute encryption support.

    Encrypted attributes are declared at the model level. These
    are regular Active Record attributes backed by a column with
    the same name. The system will transparently encrypt these
    attributes before saving them into the database and will
    decrypt them when retrieving their values.

    class Person < ApplicationRecord
      encrypts :name
      encrypts :email_address, deterministic: true
    end

    You can learn more in the Active Record Encryption
    guide
    .

    Jorge Manrubia

  • Changed Arel predications contains and overlaps to use
    quoted_node so that PostgreSQL arrays are quoted properly.

    Bradley Priest

  • Add mode argument to record level strict_loading!.

    This argument can be used when enabling strict loading for a single record
    to specify that we only want to raise on n plus one queries.

    developer.strict_loading!(mode: :n_plus_one_only)
    
    developer.projects.to_a # Does not raise
    developer.projects.first.client # Raises StrictLoadingViolationError

    Previously, enabling strict loading would cause any lazily loaded
    association to raise an error. Using n_plus_one_only mode allows us to
    lazily load belongs_to, has_many, and other associations that are fetched
    through a single query.

    Dinah Shi

  • Fix Float::INFINITY assignment to datetime column with postgresql adapter.

    Before:

    # With this config
    ActiveRecord::Base.time_zone_aware_attributes = true
    
    # and the following schema:
    create_table "postgresql_infinities" do |t|
      t.datetime "datetime"
    end
    
    # This test fails
    record = PostgresqlInfinity.create!(datetime: Float::INFINITY)
    assert_equal Float::INFINITY, record.datetime # record.datetime gets nil

    After this commit, record.datetime gets Float::INFINITY as expected.

    Shunichi Ikegami

  • Type cast enum values by the original attribute type.

    The notable thing about this change is that unknown labels will no longer match 0 on MySQL.

    class Book < ActiveRecord::Base
      enum :status, { proposed: 0, written: 1, published: 2 }
    end

    Before:

    # SELECT `books`.* FROM `books` WHERE `books`.`status` = 'prohibited' LIMIT 1
    Book.find_by(status: :prohibited)
    # => #<Book id: 1, status: "proposed", ...> (for mysql2 adapter)
    # => ActiveRecord::StatementInvalid: PG::InvalidTextRepresentation: ERROR:  invalid input syntax for type integer: "prohibited" (for postgresql adapter)
    # => nil (for sqlite3 adapter)

    After:

    # SELECT `books`.* FROM `books` WHERE `books`.`status` IS NULL LIMIT 1
    Book.find_by(status: :prohibited)
    # => nil (for all adapters)

    Ryuta Kamizono

  • Fixtures for has_many :through associations now load timestamps on join tables.

    Given this fixture:

    ### monkeys.yml
    george:
      name: George the Monkey
      fruits: apple
    
    ### fruits.yml
    apple:
      name: apple

    If the join table (fruit_monkeys) contains created_at or updated_at columns,
    these will now be populated when loading the fixture. Previously, fixture loading
    would crash if these columns were required, and leave them as null otherwise.

    Alex Ghiculescu

  • Allow applications to configure the thread pool for async queries.

    Some applications may want one thread pool per database whereas others want to use
    a single global thread pool for all queries. By default, Rails will set async_query_executor
    to nil which will not initialize any executor. If load_async is called and no executor
    has been configured, the query will be executed in the foreground.

    To create one thread pool for all database connections to use applications can set
    config.active_record.async_query_executor to :global_thread_pool and optionally define
    config.active_record.global_executor_concurrency. This defaults to 4. For applications that want
    to have a thread pool for each database connection, config.active_record.async_query_executor can
    be set to :multi_thread_pool. The configuration for each thread pool is set in the database
    configuration.

    Eileen M. Uchitelle

  • Allow new syntax for enum to avoid leading _ from reserved options.

    Before:

    class Book < ActiveRecord::Base
      enum status: [ :proposed, :written ], _prefix: true, _scopes: false
      enum cover: [ :hard, :soft ], _suffix: true, _default: :hard
    end

    After:

    class Book < ActiveRecord::Base
      enum :status, [ :proposed, :written ], prefix: true, scopes: false
      enum :cover, [ :hard, :soft ], suffix: true, default: :hard
    end

    Ryuta Kamizono

  • Add ActiveRecord::Relation#load_async.

    This method schedules the query to be performed asynchronously from a thread pool.

    If the result is accessed before a background thread had the opportunity to perform
    the query, it will be performed in the foreground.

    This is useful for queries that can be performed long enough before their result will be
    needed, or for controllers which need to perform several independent queries.

    def index
      @categories = Category.some_complex_scope.load_async
      @posts = Post.some_complex_scope.load_async
    end

    Active Record logs will also include timing info for the duration of how long
    the main thread had to wait to access the result. This timing is useful to know
    whether or not it's worth to load the query asynchronously.

    DEBUG -- :   Category Load (62.1ms)  SELECT * FROM `categories` LIMIT 50
    DEBUG -- :   ASYNC Post Load (64ms) (db time 126.1ms)  SELECT * FROM `posts` LIMIT 100
    

    The duration in the first set of parens is how long the main thread was blocked
    waiting for the results, and the second set of parens with "db time" is how long
    the entire query took to execute.

    Jean Boussier

  • Implemented ActiveRecord::Relation#excluding method.

    This method excludes the specified record (or collection of records) from
    the resulting relation:

    Post.excluding(post)
    Post.excluding(post_one, post_two)

    Also works on associations:

    post.comments.excluding(comment)
    post.comments.excluding(comment_one, comment_two)

    This is short-hand for Post.where.not(id: post.id) (for a single record)
    and Post.where.not(id: [post_one.id, post_two.id]) (for a collection).

    Glen Crawford

  • Skip optimised #exist? query when #include? is called on a relation
    with a having clause.

    Relations that have aliased select values AND a having clause that
    references an aliased select value would generate an error when
    #include? was called, due to an optimisation that would generate
    call #exists? on the relation instead, which effectively alters
    the select values of the query (and thus removes the aliased select
    values), but leaves the having clause intact. Because the having
    clause is then referencing an aliased column that is no longer
    present in the simplified query, an ActiveRecord::InvalidStatement
    error was raised.

    A sample query affected by this problem:

    Author.select('COUNT(*) as total_posts', 'authors.*')
          .joins(:posts)
          .group(:id)
          .having('total_posts > 2')
          .include?(Author.first)

    This change adds an addition check to the condition that skips the
    simplified #exists? query, which simply checks for the presence of
    a having clause.

    Fixes #41417.

    Michael Smart

  • Increment postgres prepared statement counter before making a prepared statement, so if the statement is aborted
    without Rails knowledge (e.g., if app gets killed during long-running query or due to Rack::Timeout), app won't end
    up in perpetual crash state for being inconsistent with PostgreSQL.

    wbharding, Martin Tepper

  • Add ability to apply scoping to all_queries.

    Some applications may want to use the scoping method but previously it only
    worked on certain types of queries. This change allows the scoping method to apply
    to all queries for a model in a block.

    Post.where(blog_id: post.blog_id).scoping(all_queries: true) do
      post.update(title: "a post title") # adds `posts.blog_id = 1` to the query
    end

    Eileen M. Uchitelle

  • ActiveRecord::Calculations.calculate called with :average
    (aliased as ActiveRecord::Calculations.average) will now use column-based
    type casting. This means that floating-point number columns will now be
    aggregated as Float and decimal columns will be aggregated as BigDecimal.

    Integers are handled as a special case returning BigDecimal always
    (this was the case before already).

    # With the following schema:
    create_table "measurements" do |t|
      t.float "temperature"
    end
    
    # Before:
    Measurement.average(:temperature).class
    # => BigDecimal
    
    # After:
    Measurement.average(:temperature).class
    # => Float

    Before this change, Rails just called to_d on average aggregates from the
    database adapter. This is not the case anymore. If you relied on that kind
    of magic, you now need to register your own ActiveRecord::Type
    (see ActiveRecord::Attributes::ClassMethods for documentation).

    Josua Schmid

  • PostgreSQL: introduce ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.datetime_type.

    This setting controls what native type Active Record should use when you call datetime in
    a migration or schema. It takes a symbol which must correspond to one of the configured
    NATIVE_DATABASE_TYPES. The default is :timestamp, meaning t.datetime in a migration
    will create a "timestamp without time zone" column. To use "timestamp with time zone",
    change this to :timestamptz in an initializer.

    You should run bin/rails db:migrate to rebuild your schema.rb if you change this.

    Alex Ghiculescu

  • PostgreSQL: handle timestamp with time zone columns correctly in schema.rb.

    Previously they dumped as t.datetime :column_name, now they dump as t.timestamptz :column_name,
    and are created as timestamptz columns when the schema is loaded.

    Alex Ghiculescu

  • Removing trailing whitespace when matching columns in
    ActiveRecord::Sanitization.disallow_raw_sql!.

    Gannon McGibbon, Adrian Hirt

  • Expose a way for applications to set a primary_abstract_class.

    Multiple database applications that use a primary abstract class that is not
    named ApplicationRecord can now set a specific class to be the primary_abstract_class.

    class PrimaryApplicationRecord
      self.primary_abstract_class
    end

    When an application boots it automatically connects to the primary or first database in the
    database configuration file. In a multiple database application that then call connects_to
    needs to know that the default connection is the same as the ApplicationRecord connection.
    However, some applications have a differently named ApplicationRecord. This prevents Active
    Record from opening duplicate connections to the same database.

    Eileen M. Uchitelle, John Crepezzi

  • Support hash config for structure_dump_flags and structure_load_flags flags.
    Now that Active Record supports multiple databases configuration,
    we need a way to pass specific flags for dump/load databases since
    the options are not the same for different adapters.
    We can use in the original way:

    ActiveRecord::Tasks::DatabaseTasks.structure_dump_flags = ['--no-defaults', '--skip-add-drop-table']
    # or
    ActiveRecord::Tasks::DatabaseTasks.structure_dump_flags = '--no-defaults --skip-add-drop-table'

    And also use it passing a hash, with one or more keys, where the key
    is the adapter

    ActiveRecord::Tasks::DatabaseTasks.structure_dump_flags = {
      mysql2: ['--no-defaults', '--skip-add-drop-table'],
      postgres: '--no-tablespaces'
    }

    Gustavo Gonzalez

  • Connection specification now passes the "url" key as a configuration for the
    adapter if the "url" protocol is "jdbc", "http", or "https". Previously only
    urls with the "jdbc" prefix were passed to the Active Record Adapter, others
    are assumed to be adapter specification urls.

    Fixes #41137.

    Jonathan Bracy

  • Allow to opt-out of strict_loading mode on a per-record base.

    This is useful when strict loading is enabled application wide or on a
    model level.

    class User < ApplicationRecord
      has_many :bookmarks
      has_many :articles, strict_loading: true
    end
    
    user = User.first
    user.articles                        # => ActiveRecord::StrictLoadingViolationError
    user.bookmarks                       # => #<ActiveRecord::Associations::CollectionProxy>
    
    user.strict_loading!(true)           # => true
    user.bookmarks                       # => ActiveRecord::StrictLoadingViolationError
    
    user.strict_loading!(false)          # => false
    user.bookmarks                       # => #<ActiveRecord::Associations::CollectionProxy>
    user.articles.strict_loading!(false) # => #<ActiveRecord::Associations::CollectionProxy>

    Ayrton De Craene

  • Add FinderMethods#sole and #find_sole_by to find and assert the
    presence of exactly one record.

    Used when you need a single row, but also want to assert that there aren't
    multiple rows matching the condition; especially for when database
    constraints aren't enough or are impractical.

    Product.where(["price = %?", price]).sole
    # => ActiveRecord::RecordNotFound      (if no Product with given price)
    # => #<Product ...>                    (if one Product with given price)
    # => ActiveRecord::SoleRecordExceeded  (if more than one Product with given price)
    
    user.api_keys.find_sole_by(key: key)
    # as above

    Asherah Connor

  • Makes ActiveRecord::AttributeMethods::Query respect the getter overrides defined in the model.

    Before:

    class User
      def admin
        false # Overriding the getter to always return false
      end
    end
    
    user = User.first
    user.update(admin: true)
    
    user.admin # false (as expected, due to the getter overwrite)
    user.admin? # true (not expected, returned the DB column value)

    After this commit, user.admin? above returns false, as expected.

    Fixes #40771.

    Felipe

  • Allow delegated_type to be specified primary_key and foreign_key.

    Since delegated_type assumes that the foreign_key ends with _id,
    singular_id defined by it does not work when the foreign_key does
    not end with id. This change fixes it by taking into account
    primary_key and foreign_key in the options.

    Ryota Egusa

  • Expose an invert_where method that will invert all scope conditions.

    class User
      scope :active, -> { where(accepted: true, locked: false) }
    end
    
    User.active
    # ... WHERE `accepted` = 1 AND `locked` = 0
    
    User.active.invert_where
    # ... WHERE NOT (`accepted` = 1 AND `locked` = 0)

    Kevin Deisz

  • Restore possibility of passing false to :polymorphic option of belongs_to.

    Previously, passing false would trigger the option validation logic
    to throw an error saying :polymorphic would not be a valid option.

    glaszig

  • Remove deprecated database kwarg from connected_to.

    Eileen M. Uchitelle, John Crepezzi

  • Allow adding nonnamed expression indexes to be revertible.

    Previously, the following code would raise an error, when executed while rolling back,
    and the index name should be specified explicitly. Now, the index name is inferred
    automatically.

    add_index(:items, "to_tsvector('english', description)")

    Fixes #40732.

    fatkodima

  • Only warn about negative enums if a positive form that would cause conflicts exists.

    Fixes #39065.

    Alex Ghiculescu

  • Add option to run default_scope on all queries.

    Previously, a default_scope would only run on select or insert queries. In some cases, like non-Rails tenant sharding solutions, it may be desirable to run default_scope on all queries in order to ensure queries are including a foreign key for the shard (i.e. blog_id).

    Now applications can add an option to run on all queries including select, insert, delete, and update by adding an all_queries option to the default scope definition.

    class Article < ApplicationRecord
      default_scope -> { where(blog_id: Current.blog.id) }, all_queries: true
    end

    Eileen M. Uchitelle

  • Add where.associated to check for the presence of an association.

    # Before:
    account.users.joins(:contact).where.not(contact_id: nil)
    
    # After:
    account.users.where.associated(:contact)

    Also mirrors where.missing.

    Kasper Timm Hansen

  • Allow constructors (build_association and create_association) on
    has_one :through associations.

    Santiago Perez Perret

Active Storage

  • Support transforming empty-ish has_many_attached value into [] (e.g. [""]).

    @user.highlights = [""]
    @user.highlights # => []

    Sean Doyle

  • Add ActiveStorage::Blob.compose to concatenate multiple blobs.

    Gannon McGibbon

  • Setting custom metadata on blobs are now persisted to remote storage.

    joshuamsager

  • Support direct uploads to multiple services.

    Dmitry Tsepelev

  • Invalid default content types are deprecated

    Blobs created with content_type image/jpg, image/pjpeg, image/bmp, text/javascript will now produce
    a deprecation warning, since these are not valid content types.

    These content types will be removed from the defaults in Rails 7.1.

    You can set config.active_storage.silence_invalid_content_types_warning = true to dismiss the warning.

    Alex Ghiculescu

  • Emit Active Support instrumentation events from Active Storage analyzers.

    Fixes #42930

    Shouichi Kamiya

  • Add support for byte range requests

    Tom Prats

  • Attachments can be deleted after their association is no longer defined.

    Fixes #42514

    Don Sisco

  • Make vips the default variant processor for new apps.

    See the upgrade guide for instructions on converting from mini_magick to vips. mini_magick is
    not deprecated, existing apps can keep using it.

    Breno Gazzola

  • Deprecate ActiveStorage::Current.host in favor of ActiveStorage::Current.url_options which accepts
    a host, protocol and port.

    Santiago Bartesaghi

  • Allow using IAM when signing URLs with GCS.

    gcs:
      service: GCS
      ...
      iam: true

    RRethy

  • OpenSSL constants are now used for Digest computations.

    Dirkjan Bussink

  • Deprecate config.active_storage.replace_on_assign_to_many. Future versions of Rails
    will behave the same way as when the config is set to true.

    Santiago Bartesaghi

  • Remove deprecated methods: build_after_upload, create_after_upload! in favor of create_and_upload!,
    and service_url in favor of url.

    Santiago Bartesaghi

  • Add support of strict_loading_by_default to ActiveStorage::Representations controllers.

    Anton Topchii, Andrew White

  • Allow to detach an attachment when record is not persisted.

    Jacopo Beschi

  • Use libvips instead of ImageMagick to analyze images when active_storage.variant_processor = vips.

    Breno Gazzola

  • Add metadata value for presence of video channel in video blobs.

    The metadata attribute of video blobs has a new boolean key named video that is set to
    true if the file has an video channel and false if it doesn't.

    Breno Gazzola

  • Deprecate usage of purge and purge_later from the association extension.

    Jacopo Beschi

  • Passing extra parameters in ActiveStorage::Blob#url to S3 Client.

    This allows calls of ActiveStorage::Blob#url to have more interaction with
    the S3 Presigner, enabling, amongst other options, custom S3 domain URL
    Generation.

    blob = ActiveStorage::Blob.last
    
    blob.url # => https://<bucket-name>.s3.<region>.amazonaws.com/<key>
    blob.url(virtual_host: true) # => # => https://<bucket-name>/<key>

    josegomezr

  • Allow setting a Cache-Control on files uploaded to GCS.

    gcs:
      service: GCS
      ...
      cache_control: "public, max-age=3600"

    maleblond

  • The parameters sent to ffmpeg for generating a video preview image are now
    configurable under config.active_storage.video_preview_arguments.

    Brendon Muir

  • The ActiveStorage video previewer will now use scene change detection to generate
    better preview images (rather than the previous default of using the first frame
    of the video). This change requires FFmpeg v3.4+.

    Jonathan Hefner

  • Add support for ActiveStorage expiring URLs.

    rails_blob_path(user.avatar, disposition: "attachment", expires_in: 30.minutes)
    
    <%= image_tag rails_blob_path(user.avatar.variant(resize: "100x100"), expires_in: 30.minutes) %>

    If you want to set default expiration time for ActiveStorage URLs throughout your application, set config.active_storage.urls_expire_in.

    aki77

  • Allow to purge an attachment when record is not persisted for has_many_attached.

    Jacopo Beschi

  • Add with_all_variant_records method to eager load all variant records on an attachment at once.
    with_attached_image scope now eager loads variant records if using variant tracking.

    Alex Ghiculescu

  • Add metadata value for presence of audio channel in video blobs.

    The metadata attribute of video blobs has a new boolean key named audio that is set to
    true if the file has an audio channel and false if it doesn't.

    Breno Gazzola

  • Adds analyzer for audio files.

    Breno Gazzola

  • Respect Active Record's primary_key_type in Active Storage migrations.

    fatkodima

  • Allow expires_in for ActiveStorage signed ids.

    aki77

  • Allow to purge an attachment when record is not persisted for has_one_attached.

    Jacopo Beschi

  • Add a load hook called active_storage_variant_record (providing ActiveStorage::VariantRecord)
    to allow for overriding aspects of the ActiveStorage::VariantRecord class. This makes
    ActiveStorage::VariantRecord consistent with ActiveStorage::Blob and ActiveStorage::Attachment
    that already have load hooks.

    Brendon Muir

  • ActiveStorage::PreviewError is raised when a previewer is unable to generate a preview image.

    Alex Robbin

  • Add ActiveStorage::Streaming module that can be included in a controller to get access to #send_blob_stream,
    which wraps the new ActionController::Base#send_stream method to stream a blob from cloud storage:

    class MyPublicBlobsController < ApplicationController
      include ActiveStorage::SetBlob, ActiveStorage::Streaming
    
      def show
        http_cache_forever(public: true) do
          send_blob_stream @blob, disposition: params[:disposition]
        end
      end
    end

    DHH

  • Add ability to use pre-defined variants.

    class User < ActiveRecord::Base
      has_one_attached :avatar do |attachable|
        attachable.variant :thumb, resize: "100x100"
        attachable.variant :medium, resize: "300x300", monochrome: true
      end
    end
    
    class Gallery < ActiveRecord::Base
      has_many_attached :photos do |attachable|
        attachable.variant :thumb, resize: "100x100"
        attachable.variant :medium, resize: "300x300", monochrome: true
      end
    end
    
    <%= image_tag user.avatar.variant(:thumb) %>

    fatkodima

  • After setting config.active_storage.resolve_model_to_route = :rails_storage_proxy
    rails_blob_path and rails_representation_path will generate proxy URLs by default.

    Ali Ismayilov

  • Declare ActiveStorage::FixtureSet and ActiveStorage::FixtureSet.blob to
    improve fixture integration.

    Sean Doyle

Active Support

  • Fix ActiveSupport::Duration.build to support negative values.

    The algorithm to collect the parts of the ActiveSupport::Duration
    ignored the sign of the value and accumulated incorrect part values. This
    impacted ActiveSupport::Duration#sum (which is dependent on parts) but
    not ActiveSupport::Duration#eql? (which is dependent on value).

    Caleb Buxton, Braden Staudacher

  • Deprecate passing a format to #to_s in favor of #to_formatted_s in Array, Range, Date, DateTime, Time,
    BigDecimal, Float and, Integer.

    Rafael Mendonça França

  • Document ActiveSupport::Testing::Deprecation.

    Sam Bostock & Sam Jordan

  • Add Pathname#existence.

    Pathname.new("file").existence&.read

    Timo Schilling

  • Remove deprecate ActiveSupport::Multibyte::Unicode.default_normalization_form.

    Rafael Mendonça França

  • Remove deprecated support to use Range#include? to check the inclusion of a value in
    a date time range is deprecated.

    Rafael Mendonça França

  • Remove deprecated URI.parser.

    Rafael Mendonça França

  • Remove deprecated config.active_support.use_sha1_digests.

    Rafael Mendonça França

  • Invoking Object#with_options without a &block argument returns the
    ActiveSupport::OptionMerger instance.

    Sean Doyle

  • Rails.application.executor hooks can now be called around every test

    This helps to better simulate request or job local state being reset around tests and prevents state
    leaking from one test to another.

    However it requires the executor hooks executed in the test environment to be re-entrant.

    To enable this, set config.active_support.executor_around_test_case = true (this is the default in Rails 7).

    Jean Boussier

  • ActiveSupport::DescendantsTracker now mostly delegate to Class#descendants on Ruby 3.1

    Ruby now provides a fast Class#descendants making ActiveSupport::DescendantsTracker mostly useless.

    As a result the following methods are deprecated:

    • ActiveSupport::DescendantsTracker.direct_descendants
    • ActiveSupport::DescendantsTracker#direct_descendants

    Jean Boussier

  • Fix the Digest::UUID.uuid_from_hash behavior for namespace IDs that are different from the ones defined on Digest::UUID.

    The new behavior will be enabled by setting the
    config.active_support.use_rfc4122_namespaced_uuids option to true
    and is the default for new apps.

    The old behavior is the default for upgraded apps and will output a
    deprecation warning every time a value that is different than one of
    the constants defined on the Digest::UUID extension is used as the
    namespace ID.

    Alex Robbin, Erich Soares Machado, Eugene Kenny

  • ActiveSupport::Inflector::Inflections#clear(:acronyms) is now supported,
    and inflector.clear / inflector.clear(:all) also clears acronyms.

    Alex Ghiculescu, Oliver Peate

  • ActiveSupport::Dependencies no longer installs a const_missing hook. Before this, you could push to the autoload paths and have constants autoloaded. This feature, known as the classic autoloader, has been removed.

    Xavier Noria

  • Private internal classes of ActiveSupport::Dependencies have been deleted, like ActiveSupport::Dependencies::Reference, ActiveSupport::Dependencies::Blamable, and others.

    Xavier Noria

  • The private API of ActiveSupport::Dependencies has been deleted. That includes methods like hook!, unhook!, depend_on, require_or_load, mechanism, and many others.

    Xavier Noria

  • Improves the performance of ActiveSupport::NumberHelper formatters by avoiding the use of exceptions as flow control.

    Mike Dalessio

  • Removed rescue block from ActiveSupport::Cache::RedisCacheStore#handle_exception

    Previously, if you provided a error_handler to redis_cache_store, any errors thrown by
    the error handler would be rescued and logged only. Removed the rescue clause from handle_exception
    to allow these to be thrown.

    Nicholas A. Stuart

  • Allow entirely opting out of deprecation warnings.

    Previously if you did app.config.active_support.deprecation = :silence, some work would
    still be done on each call to ActiveSupport::Deprecation.warn. In very hot paths, this could
    cause performance issues.

    Now, you can make ActiveSupport::Deprecation.warn a no-op:

    config.active_support.report_deprecations = false

    This is the default in production for new apps. It is the equivalent to:

    config.active_support.deprecation = :silence
    config.active_support.disallowed_deprecation = :silence

    but will take a more optimised code path.

    Alex Ghiculescu

  • Faster tests by parallelizing only when overhead is justified by the number
    of them.

    Running tests in parallel adds overhead in terms of database
    setup and fixture loading. Now, Rails will only parallelize test executions when
    there are enough tests to make it worth it.

    This threshold is 50 by default, and is configurable via config setting in
    your test.rb:

    config.active_support.test_parallelization_threshold = 100

    It's also configurable at the test case level:

    class ActiveSupport::TestCase
      parallelize threshold: 100
    end

    Jorge Manrubia

  • OpenSSL constants are now used for Digest computations.

    Dirkjan Bussink

  • TimeZone.iso8601 now accepts valid ordinal values similar to Ruby's Date._iso8601 method.
    A valid ordinal value will be converted to an instance of TimeWithZone using the :year
    and :yday fragments returned from Date._iso8601.

    twz = ActiveSupport::TimeZone["Eastern Time (US & Canada)"].iso8601("21087")
    twz.to_a[0, 6] == [0, 0, 0, 28, 03, 2021]

    Steve Laing

  • Time#change and methods that call it (e.g. Time#advance) will now
    return a Time with the timezone argument provided, if the caller was
    initialized with a timezone argument.

    Fixes #42467.

    Alex Ghiculescu

  • Allow serializing any module or class to JSON by name.

    Tyler Rick, Zachary Scott

  • Raise ActiveSupport::EncryptedFile::MissingKeyError when the
    RAILS_MASTER_KEY environment variable is blank (e.g. "").

    Sunny Ripert

  • The from: option is added to ActiveSupport::TestCase#assert_no_changes.

    It permits asserting on the initial value that is expected not to change.

    assert_no_changes -> { Status.all_good? }, from: true do
      post :create, params: { status: { ok: true } }
    end

    George Claghorn

  • Deprecate ActiveSupport::SafeBuffer's incorrect implicit conversion of objects into string.

    Except for a few methods like String#%, objects must implement #to_str
    to be implicitly converted to a String in string operations. In some
    circumstances ActiveSupport::SafeBuffer was incorrectly calling the
    explicit conversion method (#to_s) on them. This behavior is now
    deprecated.

    Jean Boussier

  • Allow nested access to keys on Rails.application.credentials.

    Previously only top level keys in credentials.yml.enc could be accessed with method calls. Now any key can.

    For example, given these secrets:

    aws:
      access_key_id: 123
      secret_access_key: 345

    Rails.application.credentials.aws.access_key_id will now return the same thing as
    Rails.application.credentials.aws[:access_key_id].

    Alex Ghiculescu

  • Added a faster and more compact ActiveSupport::Cache serialization format.

    It can be enabled with config.active_support.cache_format_version = 7.0 or
    config.load_defaults 7.0. Regardless of the configuration Active Support
    7.0 can read cache entries serialized by Active Support 6.1 which allows to
    upgrade without invalidating the cache. However Rails 6.1 can't read the
    new format, so all readers must be upgraded before the new format is enabled.

    Jean Boussier

  • Add Enumerable#sole, per ActiveRecord::FinderMethods#sole. Returns the
    sole item of the enumerable, raising if no items are found, or if more than
    one is.

    Asherah Connor

  • Freeze ActiveSupport::Duration#parts and remove writer methods.

    Durations are meant to be value objects and should not be mutated.

    Andrew White

  • Fix ActiveSupport::TimeZone#utc_to_local with fractional seconds.

    When utc_to_local_returns_utc_offset_times is false and the time
    instance had fractional seconds the new UTC time instance was out by
    a factor of 1,000,000 as the Time.utc constructor takes a usec
    value and not a fractional second value.

    Andrew White

  • Add expires_at argument to ActiveSupport::Cache write and fetch to set a cache entry TTL as an absolute time.

    Rails.cache.write(key, value, expires_at: Time.now.at_end_of_hour)

    Jean Boussier

  • Deprecate ActiveSupport::TimeWithZone.name so that from Rails 7.1 it will use the default implementation.

    Andrew White

  • Deprecates Rails custom Enumerable#sum and Array#sum in favor of Ruby's native implementation which
    is considerably faster.

    Ruby requires an initializer for non-numeric type as per examples below:

    %w[foo bar].sum('')
    # instead of %w[foo bar].sum
    
    [[1, 2], [3, 4, 5]].sum([])
    # instead of [[1, 2], [3, 4, 5]].sum

    Alberto Mota

  • Tests parallelization is now disabled when running individual files to prevent the setup overhead.

    It can still be enforced if the environment variable PARALLEL_WORKERS is present and set to a value greater than 1.

    Ricardo Díaz

  • Fix proxying keyword arguments in ActiveSupport::CurrentAttributes.

    Marcin Kołodziej

  • Add Enumerable#maximum and Enumerable#minimum to easily calculate the maximum or minimum from extracted
    elements of an enumerable.

    payments = [Payment.new(5), Payment.new(15), Payment.new(10)]
    
    payments.minimum(:price) # => 5
    payments.maximum(:price) # => 15

    This also allows passing enumerables to fresh_when and stale? in Action Controller.
    See PR #41404 for an example.

    Ayrton De Craene

  • ActiveSupport::Cache::MemCacheStore now accepts an explicit nil for its addresses argument.

    config.cache_store = :mem_cache_store, nil
    
    # is now equivalent to
    
    config.cache_store = :mem_cache_store
    
    # and is also equivalent to
    
    config.cache_store = :mem_cache_store, ENV["MEMCACHE_SERVERS"] || "localhost:11211"
    
    # which is the fallback behavior of Dalli

    This helps those migrating from :dalli_store, where an explicit nil was permitted.

    Michael Overmeyer

  • Add Enumerable#in_order_of to put an Enumerable in a certain order by a key.

    DHH

  • ActiveSupport::Inflector.camelize behaves expected when provided a symbol :upper or :lower argument. Matches
    String#camelize behavior.

    Alex Ghiculescu

  • Raises an ArgumentError when the first argument of ActiveSupport::Notification.subscribe is
    invalid.

    Vipul A M

  • HashWithIndifferentAccess#deep_transform_keys now returns a HashWithIndifferentAccess instead of a Hash.

    Nathaniel Woodthorpe

  • Consume dalli’s cache_nils configuration as ActiveSupport::Cache's skip_nil when using MemCacheStore.

    Ritikesh G

  • Add RedisCacheStore#stats method similar to MemCacheStore#stats. Calls redis#info internally.

    Ritikesh G

Guides

  • The autoloading guide for zeitwerk mode has been revised.

    Xavier Noria

  • The autoloading guide for classic mode has been deleted.

    Xavier Noria

Railtie

  • Allow localhost with a port by default in development

    [Fixes: #43864]

  • Remove deprecated config in dbconsole.

    Rafael Mendonça França

  • Change default X-XSS-Protection header to disable XSS auditor

    This header has been deprecated and the XSS auditor it triggered
    has been removed from all major modern browsers (in favour of
    Content Security Policy) that implemented this header to begin with
    (Firefox never did).

    OWASP
    suggests setting this header to '0' to disable the default behaviour
    on old browsers as it can introduce additional security issues.

    Added the new behaviour as a framework default from Rails 7.0.

    Christian Sutter

  • Scaffolds now use date_field, time_field and datetime_field instead of
    date_select, time_select and datetime_select; thus providing native date/time pickers.

    Martijn Lafeber

  • Fix a regression in which autoload paths were initialized too late.

    Xavier Noria

  • Fix activestorage dependency in the npm package.

    Rafael Mendonça França

  • New and upgraded Rails apps no longer generate config/initializers/application_controller_renderer.rb
    or config/initializers/cookies_serializer.rb

    The default value for cookies_serializer (:json) has been moved to config.load_defaults("7.0").
    The new framework defaults file can be used to upgrade the serializer.

    Alex Ghiculescu

  • New applications get a dependency on the new debug gem, replacing byebug.

    Xavier Noria

  • Add SSL support for postgresql in bin/rails dbconsole.

    Fixes #43114.

    Michael Bayucot

  • Add support for comments above gem declaration in Rails application templates, e.g. gem("nokogiri", comment: "For XML").

    Linas Juškevičius

  • The setter config.autoloader= has been deleted. zeitwerk is the only
    available autoloading mode.

    Xavier Noria

  • config.autoload_once_paths can be configured in the body of the
    application class defined in config/application.rb or in the configuration
    for environments in config/environments/*.

    Similarly, engines can configure that collection in the class body of the
    engine class or in the configuration for environments.

    After that, the collection is frozen, and you can autoload from those paths.
    They are managed by the Rails.autoloaders.once autoloader, which does not
    reload, only autoloads/eager loads.

    Xavier Noria

  • During initialization, you cannot autoload reloadable classes or modules
    like application models, unless they are wrapped in a to_prepare block.
    For example, from config/initializers/*, or in application, engines, or
    railties initializers.

    Please check the autoloading
    guide

    for details.

    Xavier Noria

  • While they are allowed to have elements in common, it is no longer required
    that config.autoload_once_paths is a subset of config.autoload_paths.
    The former are managed by the once autoloader. The main autoloader
    manages the latter minus the former.

    Xavier Noria

  • Show Rake task description if command is run with -h.

    Adding -h (or --help) to a Rails command that's a Rake task now outputs
    the task description instead of the general Rake help.

    Petrik de Heus

  • Add missing plugin new command to help.

    *Petrik de Heus

  • Fix config_for error when there's only a shared root array.

    Loïc Delmaire

  • Raise an error in generators if an index type is invalid.

    Petrik de Heus

  • package.json now uses a strict version constraint for Rails JavaScript packages on new Rails apps.

    Zachary Scott, Alex Ghiculescu

  • Modified scaffold generator template so that running
    rails g scaffold Author no longer generates tests called "creating
    a Author", "updating a Author", and "destroying a Author".

    Fixes #40744.

    Michael Duchemin

  • Raise an error in generators if a field type is invalid.

    Petrik de Heus

  • bin/rails tmp:clear deletes also files and directories in tmp/storage.

    George Claghorn

  • Fix compatibility with psych >= 4.

    Starting in Psych 4.0.0 YAML.load behaves like YAML.safe_load. To preserve compatibility
    Rails.application.config_for now uses YAML.unsafe_load if available.

    Jean Boussier

  • Allow loading nested locales in engines.

    Gannon McGibbon

  • Ensure Rails.application.config_for always cast hashes to ActiveSupport::OrderedOptions.

    Jean Boussier

  • Remove Rack::Runtime from the default middleware stack and deprecate
    referencing it in middleware operations without adding it back.

    Hartley McGuire

  • Allow adding additional authorized hosts in development via ENV['RAILS_DEVELOPMENT_HOSTS'].

    Josh Abernathy, Debbie Milburn

  • Add app concern and test keepfiles to generated engine plugins.

    Gannon McGibbon

  • Stop generating a license for in-app plugins.

    Gannon McGibbon

  • rails app:update no longer prompts you to overwrite files that are generally modified in the
    course of developing a Rails app. See #41083 for
    the full list of changes.

    Alex Ghiculescu

  • Change default branch for new Rails projects and plugins to main.

    Prateek Choudhary

  • The new method Rails.benchmark gives you a quick way to measure and log the execution time taken by a block:

    def test_expensive_stuff
      Rails.benchmark("test_expensive_stuff") { ... }
    end
    

    This functionality was available in some contexts only before.

    Simon Perepelitsa

  • Applications generated with --skip-sprockets no longer get app/assets/config/manifest.js and app/assets/stylesheets/application.css.

    Cindy Gao

  • Add support for stylesheets and ERB views to rails stats.

    Joel Hawksley

  • Allow appended root routes to take precedence over internal welcome controller.

    Gannon McGibbon

Don't miss a new rails release

NewReleases is sending notifications on new releases.