Skip to content

Commit 43226af

Browse files
authored
Merge pull request rails#43535 from Shopify/remove-query-logs-null-object
Refactor ActiveRecord::QueryLogs context API
2 parents 0591b7a + 51c45d3 commit 43226af

File tree

5 files changed

+32
-46
lines changed

5 files changed

+32
-46
lines changed

actionpack/lib/action_controller/railtie.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,9 @@ class Railtie < Rails::Railtie # :nodoc:
119119

120120
ActiveSupport.on_load(:active_record) do
121121
ActiveRecord::QueryLogs.taggings.merge!(
122-
controller: ->(context) { context[:controller].controller_name },
123-
action: ->(context) { context[:controller].action_name },
124-
namespaced_controller: ->(context) { context[:controller].class.name }
122+
controller: ->(context) { context[:controller]&.controller_name },
123+
action: ->(context) { context[:controller]&.action_name },
124+
namespaced_controller: ->(context) { context[:controller].class.name if context[:controller] }
125125
)
126126
end
127127
end

activejob/lib/active_job/railtie.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ class Railtie < Rails::Railtie # :nodoc:
7070
end
7171

7272
ActiveSupport.on_load(:active_record) do
73-
ActiveRecord::QueryLogs.taggings[:job] = ->(context) { context[:job].class.name unless context[:job].nil? }
73+
ActiveRecord::QueryLogs.taggings[:job] = ->(context) { context[:job].class.name if context[:job] }
7474
end
7575
end
7676
end

activerecord/lib/active_record/query_logs.rb

Lines changed: 20 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -38,24 +38,24 @@ module ActiveRecord
3838
# tags = [
3939
# :application,
4040
# {
41-
# custom_tag: ->(context) { context[:controller].controller_name },
41+
# custom_tag: ->(context) { context[:controller]&.controller_name },
4242
# custom_value: -> { Custom.value },
4343
# }
4444
# ]
4545
# ActiveRecord::QueryLogs.tags = tags
4646
#
47-
# The QueryLogs +context+ can be manipulated via +update_context+ & +set_context+ methods.
48-
#
49-
# Direct updates to a context value:
50-
#
51-
# ActiveRecord::QueryLogs.update_context(foo: Bar.new)
47+
# The QueryLogs +context+ can be manipulated via the +set_context+ method.
5248
#
5349
# Temporary updates limited to the execution of a block:
5450
#
5551
# ActiveRecord::QueryLogs.set_context(foo: Bar.new) do
5652
# posts = Post.all
5753
# end
5854
#
55+
# Direct updates to a context value:
56+
#
57+
# ActiveRecord::QueryLogs.set_context(foo: Bar.new)
58+
#
5959
# Tag comments can be prepended to the query:
6060
#
6161
# ActiveRecord::QueryLogs.prepend_comment = true
@@ -75,39 +75,25 @@ module QueryLogs
7575
mattr_accessor :cache_query_log_tags, instance_accessor: false, default: false
7676
thread_mattr_accessor :cached_comment, instance_accessor: false
7777

78-
class NullObject # :nodoc:
79-
def method_missing(method, *args, &block)
80-
NullObject.new
81-
end
82-
83-
def nil?
84-
true
85-
end
86-
87-
private
88-
def respond_to_missing?(method, include_private = false)
89-
true
90-
end
91-
end
92-
9378
class << self
9479
# Updates the context used to construct tags in the SQL comment.
95-
# Resets the cached comment if <tt>cache_query_log_tags</tt> is +true+.
96-
def update_context(**options)
97-
context.merge!(**options.symbolize_keys)
98-
self.cached_comment = nil
99-
end
100-
101-
# Updates the context used to construct tags in the SQL comment during
102-
# execution of the provided block. Resets the provided keys to their
80+
# If a block is given, it resets the provided keys to their
10381
# previous value once the block exits.
10482
def set_context(**options)
83+
options.symbolize_keys!
84+
10585
keys = options.keys
10686
previous_context = keys.zip(context.values_at(*keys)).to_h
107-
update_context(**options)
108-
yield if block_given?
109-
ensure
110-
update_context(**previous_context)
87+
context.merge!(options)
88+
self.cached_comment = nil
89+
if block_given?
90+
begin
91+
yield
92+
ensure
93+
context.merge!(previous_context)
94+
self.cached_comment = nil
95+
end
96+
end
11197
end
11298

11399
def call(sql) # :nodoc:
@@ -137,7 +123,7 @@ def uncached_comment
137123
end
138124

139125
def context
140-
Thread.current[:active_record_query_log_tags_context] ||= Hash.new { NullObject.new }
126+
Thread.current[:active_record_query_log_tags_context] ||= {}
141127
end
142128

143129
def escape_sql_comment(content)

activerecord/test/cases/query_logs_test.rb

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -112,12 +112,12 @@ def test_retrieves_comment_from_cache_when_enabled_and_set
112112

113113
def test_resets_cache_on_context_update
114114
ActiveRecord::QueryLogs.cache_query_log_tags = true
115-
ActiveRecord::QueryLogs.update_context(temporary: "value")
115+
ActiveRecord::QueryLogs.set_context(temporary: "value")
116116
ActiveRecord::QueryLogs.tags = [ temporary_tag: ->(context) { context[:temporary] } ]
117117

118118
assert_equal "/*temporary_tag:value*/", ActiveRecord::QueryLogs.call("")
119119

120-
ActiveRecord::QueryLogs.update_context(temporary: "new_value")
120+
ActiveRecord::QueryLogs.set_context(temporary: "new_value")
121121

122122
assert_nil ActiveRecord::QueryLogs.cached_comment
123123
assert_equal "/*temporary_tag:new_value*/", ActiveRecord::QueryLogs.call("")
@@ -128,13 +128,13 @@ def test_resets_cache_on_context_update
128128

129129
def test_ensure_context_has_symbol_keys
130130
ActiveRecord::QueryLogs.tags = [ new_key: ->(context) { context[:symbol_key] } ]
131-
ActiveRecord::QueryLogs.update_context("symbol_key" => "symbolized")
131+
ActiveRecord::QueryLogs.set_context("symbol_key" => "symbolized")
132132

133133
assert_sql(%r{/\*new_key:symbolized}) do
134134
Dashboard.first
135135
end
136136
ensure
137-
ActiveRecord::QueryLogs.update_context(application_name: nil)
137+
ActiveRecord::QueryLogs.set_context(application_name: nil)
138138
end
139139

140140
def test_default_tag_behavior
@@ -197,14 +197,14 @@ def test_multiple_custom_tags
197197

198198
def test_custom_proc_context_tags
199199
original_tags = ActiveRecord::QueryLogs.tags
200-
ActiveRecord::QueryLogs.update_context(foo: "bar")
200+
ActiveRecord::QueryLogs.set_context(foo: "bar")
201201
ActiveRecord::QueryLogs.tags = [ :application, { custom_context_proc: ->(context) { context[:foo] } } ]
202202

203203
assert_sql(%r{/\*application:active_record,custom_context_proc:bar\*/$}) do
204204
Dashboard.first
205205
end
206206
ensure
207-
ActiveRecord::QueryLogs.update_context(foo: nil)
207+
ActiveRecord::QueryLogs.set_context(foo: nil)
208208
ActiveRecord::QueryLogs.tags = original_tags
209209
end
210210

railties/test/application/query_logs_test.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ def app
123123
test "query cache is cleared between requests" do
124124
add_to_config "config.active_record.query_log_tags_enabled = true"
125125
add_to_config "config.active_record.cache_query_log_tags = true"
126-
add_to_config "config.active_record.query_log_tags = [ { dynamic: ->(context) { context[:controller].dynamic_content } } ]"
126+
add_to_config "config.active_record.query_log_tags = [ { dynamic: ->(context) { context[:controller]&.dynamic_content } } ]"
127127

128128
boot_app
129129

@@ -141,7 +141,7 @@ def app
141141
test "query cache is cleared between job executions" do
142142
add_to_config "config.active_record.query_log_tags_enabled = true"
143143
add_to_config "config.active_record.cache_query_log_tags = true"
144-
add_to_config "config.active_record.query_log_tags = [ { dynamic: ->(context) { context[:job].dynamic_content } } ]"
144+
add_to_config "config.active_record.query_log_tags = [ { dynamic: ->(context) { context[:job]&.dynamic_content } } ]"
145145

146146
boot_app
147147

0 commit comments

Comments
 (0)