columns and column_names cache the schema definition, so the return value will not change after a migration.
However, the attributes method is always affected by the latest DB schema.
This behavior can cause problems when adding new columns in rolling deployments.
This is because older revisions of the Rails server do not support the new columns.
Steps to reproduce
# frozen_string_literal: true
require "bundler/inline"
gemfile(true) do
source "https://rubygems.org"
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
gem "rails"
gem "sqlite3"
end
require "active_record"
require "minitest/autorun"
require "logger"
# This connection will do for database-independent bug reports.
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
ActiveRecord::Base.logger = Logger.new(STDOUT)
ActiveRecord::Schema.define do
create_table :posts, force: true do |t|
end
end
class AddTitleToPost < ActiveRecord::Migration[7.1]
def self.up
add_column :posts, :title, :string
end
end
class Post < ActiveRecord::Base
end
class BugTest < Minitest::Test
def test_post_attributes
Post.create!
post1 = Post.first
assert_equal({ "id" => post1.id }, post1.attributes)
AddTitleToPost.up
# `.columns` and `.column_names` returns column information before migration.
assert_equal 1, Post.columns.size
assert_equal ["id"], Post.column_names
# Caching is effective if the same SQL is specified, so add SQL comments to avoid it.
post2 = Post.annotate("after migration").first
assert_equal({ "id" => post2.id }, post2.attributes)
# Failure:
# BugTest#test_post_attributes [issue.rb:51]:
# Expected: {"id"=>1}
# Actual: {"id"=>1, "title"=>nil}
end
end
Expected behavior
I think the attributes method should return a Hash that matches the information before migration, similar to columns and column_names.
Actual behavior
The attributes method includes the same columns as the latest DB schema.
System configuration
Rails version: v7.1.2
Ruby version: v3.3.0
Additional information
Using column_names allows you to use attributes safely in rolling deployments.
Summary
columns
andcolumn_names
cache the schema definition, so the return value will not change after a migration. However, theattributes
method is always affected by the latest DB schema.This behavior can cause problems when adding new columns in rolling deployments. This is because older revisions of the Rails server do not support the new columns.
Steps to reproduce
Expected behavior
I think the attributes method should return a Hash that matches the information before migration, similar to
columns
andcolumn_names
.Actual behavior
The
attributes
method includes the same columns as the latest DB schema.System configuration
Rails version: v7.1.2
Ruby version: v3.3.0
Additional information
Using
column_names
allows you to use attributes safely in rolling deployments.But this code is not cool.