What is ar_internal_metadata?
The ar_internal_metadata table is an essential part of Ruby on Rails, used to track the environment in which our application data resides.
Why does ar_internal_metadata exist?
Introduced in Rails 5, the ar_internal_metadata table helps prevent accidental loss of production data by verifying the environment before running potentially destructive commands.
When running commands such as:
rails db:schema:loadrails db:resetrails db:drop
The content of ar_internal_metadata is verified and if it indicates that the database is from a production environment, the command will fail with this error:
ActiveRecord::ProtectedEnvironmentError: You are attempting to run a destructive action against your 'production' database.
If you are sure you want to continue, run the same command with the environment variable:
DISABLE_DATABASE_ENVIRONMENT_CHECK=1
That is good because we could mistakenly run these commands in a production or run them in a development environment that is pointing to a production database.
I know what you’re thinking—we would never do that, right? But in reality, even the most careful developers can make mistakes, so it’s always good to have an extra layer of protection. 😇
How does ar_internal_metadata work?
Rails automatically generates the ar_internal_metadata table with the following structure:
key–VARCHARvalue–VARCHARupdated_at–timestampcreated_at–timestamp
This table is created or updated after every migration. You can inspect its contents with the by running the following SQL query in rails console:
ActiveRecord::Base.connection.execute("SELECT * FROM ar_internal_metadata;")
It has one row with this structure:
=> [{"key"=>"environment", "value"=>"development", "created_at"=>"...", "updated_at"=>"..."}]
Bonus: changing the table name
If you ever need to change the name used for this table, you can do that with this piece of code:
Rails.application.configure do
config.active_record.internal_metadata_table_name = 'custom_ar_internal_metadata'
end
This method is defined the ActiveRecord::ModelSchema module. You can read more about it here:
https://edgeapi.rubyonrails.org/classes/ActiveRecord/ModelSchema.html
Conclusion
While this is a crucial layer of protection, if you absolutely need to run a destructive command, you can bypass the check by setting the environment variable:
DISABLE_DATABASE_ENVIRONMENT_CHECK=1 rails db:drop
Subscribe to my newsletter!
I share content about Software Development & Architecture, Entrepreneurship and Lifelong Learning




