Skip to content

Commit 7f5fbd9

Browse files
committed
Ensure locals are fixed
1 parent d910021 commit 7f5fbd9

2 files changed

Lines changed: 86 additions & 6 deletions

File tree

lib/rubocop/cop/github/rails_view_render_literal.rb

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ module RuboCop
66
module Cop
77
module GitHub
88
class RailsViewRenderLiteral < Cop
9-
MSG = "render must be used with a string literal or an instance of a Class"
9+
MSG = "render must be used with a literal template and use literals for locals keys"
1010

1111
def_node_matcher :literal?, <<-PATTERN
1212
({str sym true false nil?} ...)
@@ -20,11 +20,11 @@ class RailsViewRenderLiteral < Cop
2020
(send nil? {:render :render_to_string} ({str sym} $_) $...)
2121
PATTERN
2222

23-
def_node_matcher :render_inst?, <<-PATTERN
23+
def_node_matcher :render_view_component?, <<-PATTERN
2424
(send nil? {:render :render_to_string} (send _ :new ...) ...)
2525
PATTERN
2626

27-
def_node_matcher :render_collection?, <<-PATTERN
27+
def_node_matcher :render_view_component_collection?, <<-PATTERN
2828
(send nil? {:render :render_to_string} (send _ :with_collection ...) ...)
2929
PATTERN
3030

@@ -38,6 +38,12 @@ class RailsViewRenderLiteral < Cop
3838
}) $_)
3939
PATTERN
4040

41+
def_node_matcher :locals_key?, <<-PATTERN
42+
(pair (sym {
43+
:locals
44+
}) $_)
45+
PATTERN
46+
4147
def_node_matcher :partial_key?, <<-PATTERN
4248
(pair (sym {
4349
:file
@@ -47,10 +53,17 @@ class RailsViewRenderLiteral < Cop
4753
}) $_)
4854
PATTERN
4955

56+
def hash_with_literal_keys?(hash)
57+
hash.pairs.all? { |pair| literal?(pair.key) }
58+
end
59+
5060
def on_send(node)
5161
return unless render?(node)
5262

53-
if render_literal?(node) || render_inst?(node) || render_collection?(node)
63+
# Ignore "component"-style renders
64+
return if render_view_component?(node) || render_view_component_collection?(node)
65+
66+
if render_literal?(node)
5467
elsif option_pairs = render_with_options?(node)
5568
if option_pairs.any? { |pair| ignore_key?(pair) }
5669
return
@@ -59,12 +72,31 @@ def on_send(node)
5972
if partial_node = option_pairs.map { |pair| partial_key?(pair) }.compact.first
6073
if !literal?(partial_node)
6174
add_offense(node, location: :expression)
75+
return
6276
end
6377
else
6478
add_offense(node, location: :expression)
79+
return
6580
end
6681
else
6782
add_offense(node, location: :expression)
83+
return
84+
end
85+
86+
if render_literal?(node) && node.arguments.count > 1
87+
locals = node.arguments[1]
88+
elsif options_pairs = render_with_options?(node)
89+
locals = option_pairs.map { |pair| locals_key?(pair) }.compact.first
90+
end
91+
92+
if locals
93+
if locals.hash_type?
94+
if !hash_with_literal_keys?(locals)
95+
add_offense(node, location: :expression)
96+
end
97+
else
98+
add_offense(node, location: :expression)
99+
end
68100
end
69101
end
70102
end

test/test_rails_view_render_literal.rb

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def test_render_variable_offense
4343
ERB
4444

4545
assert_equal 2, cop.offenses.count
46-
assert_equal "render must be used with a string literal or an instance of a Class", cop.offenses[0].message
46+
assert_equal "render must be used with a literal template and use literals for locals keys", cop.offenses[0].message
4747
end
4848

4949
def test_render_component_no_offense
@@ -94,7 +94,7 @@ def test_render_layout_variable_literal_no_offense
9494
ERB
9595

9696
assert_equal 1, cop.offenses.count
97-
assert_equal "render must be used with a string literal or an instance of a Class", cop.offenses[0].message
97+
assert_equal "render must be used with a literal template and use literals for locals keys", cop.offenses[0].message
9898
end
9999

100100
def test_render_inline_no_offense
@@ -112,4 +112,52 @@ def test_render_template_literal_no_offense
112112

113113
assert_equal 0, cop.offenses.count
114114
end
115+
116+
def test_render_literal_static_locals_no_offense
117+
erb_investigate cop, <<-ERB, "app/views/products/index.html.erb"
118+
<%= render "products/product", product: product %>
119+
ERB
120+
121+
assert_equal 0, cop.offenses.count
122+
end
123+
124+
def test_render_literal_dynamic_locals_offense
125+
erb_investigate cop, <<-ERB, "app/views/products/index.html.erb"
126+
<%= render "products/product", locals %>
127+
ERB
128+
129+
assert_equal 1, cop.offenses.count
130+
end
131+
132+
def test_render_literal_dynamic_local_key_offense
133+
erb_investigate cop, <<-ERB, "app/views/products/index.html.erb"
134+
<%= render "products/product", { product_key => product } %>
135+
ERB
136+
137+
assert_equal 1, cop.offenses.count
138+
end
139+
140+
def test_render_options_static_locals_no_offense
141+
erb_investigate cop, <<-ERB, "app/views/products/index.html.erb"
142+
<%= render partial: "products/product", locals: { product: product } %>
143+
ERB
144+
145+
assert_equal 0, cop.offenses.count
146+
end
147+
148+
def test_render_options_dynamic_locals_offense
149+
erb_investigate cop, <<-ERB, "app/views/products/index.html.erb"
150+
<%= render partial: "products/product", locals: locals %>
151+
ERB
152+
153+
assert_equal 1, cop.offenses.count
154+
end
155+
156+
def test_render_options_dynamic_local_key_offense
157+
erb_investigate cop, <<-ERB, "app/views/products/index.html.erb"
158+
<%= render partial: "products/product", locals: { product_key => product } %>
159+
ERB
160+
161+
assert_equal 1, cop.offenses.count
162+
end
115163
end

0 commit comments

Comments
 (0)