Skip to content

Commit b5fcf15

Browse files
authored
Merge pull request rails#43075 from eileencodes/add-ignore-tables-to-schema-cache
Add ability to ignore tables in the schema cache
2 parents 1b2fa18 + e3b4a46 commit b5fcf15

File tree

4 files changed

+82
-2
lines changed

4 files changed

+82
-2
lines changed

activerecord/CHANGELOG.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,21 @@
1+
* Add config option for ignoring tables when dumping the schema cache.
2+
3+
Applications can now be configured to ignore certain tables when dumping the schema cache.
4+
5+
The configuration option can table an array of tables:
6+
7+
```ruby
8+
config.active_record.schema_cache_ignored_tables = ["ignored_table", "another_ignored_table"]
9+
```
10+
11+
Or a regex:
12+
13+
```ruby
14+
config.active_record.schema_cache_ignored_tables = [/^_/]
15+
```
16+
17+
*Eileen M. Uchitelle*
18+
119
* Make schema cache methods return consistent results.
220

321
Previously the schema cache methods `primary_keys`, `columns, `columns_hash`, and `indexes`

activerecord/lib/active_record.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,12 @@ module Tasks
170170
autoload :TestDatabases, "active_record/test_databases"
171171
autoload :TestFixtures, "active_record/fixtures"
172172

173+
# A list of tables or regex's to match tables to ignore when
174+
# dumping the schema cache. For example if this is set to +[/^_/]+
175+
# the schema cache will not dump tables named with an underscore.
176+
singleton_class.attr_accessor :schema_cache_ignored_tables
177+
self.schema_cache_ignored_tables = []
178+
173179
singleton_class.attr_accessor :legacy_connection_handling
174180
self.legacy_connection_handling = true
175181

activerecord/lib/active_record/connection_adapters/schema_cache.rb

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ def primary_keys(table_name)
8686

8787
# A cached lookup for table existence.
8888
def data_source_exists?(name)
89+
return if ignored_table?(name)
8990
prepare_data_sources if @data_sources.empty?
9091
return @data_sources[name] if @data_sources.key? name
9192

@@ -108,6 +109,10 @@ def data_sources(name)
108109

109110
# Get the columns for a table
110111
def columns(table_name)
112+
if ignored_table?(table_name)
113+
raise ActiveRecord::StatementInvalid, "Table '#{table_name}' doesn't exist"
114+
end
115+
111116
@columns.fetch(table_name) do
112117
@columns[deep_deduplicate(table_name)] = deep_deduplicate(connection.columns(table_name))
113118
end
@@ -166,7 +171,7 @@ def clear_data_source_cache!(name)
166171

167172
def dump_to(filename)
168173
clear!
169-
connection.data_sources.each { |table| add(table) }
174+
tables_to_cache.each { |table| add(table) }
170175
open(filename) { |f|
171176
if filename.include?(".dump")
172177
f.write(Marshal.dump(self))
@@ -190,6 +195,18 @@ def marshal_load(array)
190195
end
191196

192197
private
198+
def tables_to_cache
199+
connection.data_sources.reject do |table|
200+
ignored_table?(table)
201+
end
202+
end
203+
204+
def ignored_table?(table_name)
205+
ActiveRecord.schema_cache_ignored_tables.any? do |ignored|
206+
ignored === table_name
207+
end
208+
end
209+
193210
def reset_version!
194211
@version = connection.migration_context.current_version
195212
end
@@ -216,7 +233,9 @@ def deep_deduplicate(value)
216233
end
217234

218235
def prepare_data_sources
219-
connection.data_sources.each { |source| @data_sources[source] = true }
236+
tables_to_cache.each do |source|
237+
@data_sources[source] = true
238+
end
220239
end
221240

222241
def open(filename)

activerecord/test/cases/connection_adapters/schema_cache_test.rb

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,43 @@ def test_marshal_dump_and_load_via_disk
220220
tempfile.unlink
221221
end
222222

223+
def test_marshal_dump_and_load_with_ignored_tables
224+
old_ignore = ActiveRecord.schema_cache_ignored_tables
225+
ActiveRecord.schema_cache_ignored_tables = ["p_schema_migrations"]
226+
# Create an empty cache.
227+
cache = SchemaCache.new @connection
228+
229+
tempfile = Tempfile.new(["schema_cache-", ".dump"])
230+
# Dump it. It should get populated before dumping.
231+
cache.dump_to(tempfile.path)
232+
233+
# Load a new cache.
234+
cache = SchemaCache.load_from(tempfile.path)
235+
cache.connection = @connection
236+
237+
# Assert a table in the cache
238+
assert cache.data_sources("posts"), "expected posts to be in the cached data_sources"
239+
assert_equal 12, cache.columns("posts").size
240+
assert_equal 12, cache.columns_hash("posts").size
241+
assert cache.data_sources("posts")
242+
assert_equal "id", cache.primary_keys("posts")
243+
assert_equal 1, cache.indexes("posts").size
244+
245+
# Assert ignored table. Behavior should match non-existent table.
246+
assert_nil cache.data_sources("p_schema_migrations"), "expected comments to not be in the cached data_sources"
247+
assert_raises ActiveRecord::StatementInvalid do
248+
cache.columns("p_schema_migrations")
249+
end
250+
assert_raises ActiveRecord::StatementInvalid do
251+
cache.columns_hash("p_schema_migrations").size
252+
end
253+
assert_nil cache.primary_keys("p_schema_migrations")
254+
assert_equal [], cache.indexes("p_schema_migrations")
255+
ensure
256+
tempfile.unlink
257+
ActiveRecord.schema_cache_ignored_tables = old_ignore
258+
end
259+
223260
def test_marshal_dump_and_load_with_gzip
224261
# Create an empty cache.
225262
cache = SchemaCache.new @connection

0 commit comments

Comments
 (0)