Skip to content

Commit 54f3e11

Browse files
committed
Check for local key literals in controllers
1 parent 6c39739 commit 54f3e11

File tree

4 files changed

+94
-11
lines changed

4 files changed

+94
-11
lines changed

lib/rubocop/cop/github/rails_controller_render_literal.rb

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,9 @@ class RailsControllerRenderLiteral < Cop
5454
def on_send(node)
5555
return unless render?(node)
5656

57-
if render_literal?(node) || render_view_component?(node) || render_const?(node)
57+
return if render_view_component?(node) || render_const?(node)
58+
59+
if render_literal?(node)
5860
elsif option_pairs = render_with_options?(node)
5961
option_pairs = option_pairs.reject { |pair| options_key?(pair) }
6062

@@ -65,18 +67,40 @@ def on_send(node)
6567
if template_node = option_pairs.map { |pair| template_key?(pair) }.compact.first
6668
if !literal?(template_node)
6769
add_offense(node, location: :expression)
70+
return
6871
end
6972
else
7073
add_offense(node, location: :expression)
74+
return
7175
end
7276

7377
if layout_node = option_pairs.map { |pair| layout_key?(pair) }.compact.first
7478
if !literal?(layout_node)
7579
add_offense(node, location: :expression)
80+
return
7681
end
7782
end
7883
else
7984
add_offense(node, location: :expression)
85+
return
86+
end
87+
88+
if render_literal?(node)
89+
option_hash = node.arguments[1]
90+
if option_hash && !option_hash.hash_type?
91+
add_offense(node, location: :expression)
92+
return
93+
end
94+
option_pairs = option_hash && option_hash.pairs
95+
else
96+
option_pairs = node.arguments[0].pairs
97+
end
98+
99+
if option_pairs
100+
locals = option_pairs.map { |pair| locals_key?(pair) }.compact.first
101+
if locals && (!locals.hash_type? || !hash_with_literal_keys?(locals))
102+
add_offense(node, location: :expression)
103+
end
80104
end
81105
end
82106
end

lib/rubocop/cop/github/rails_view_render_literal.rb

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,6 @@ class RailsViewRenderLiteral < Cop
1717
}) $_)
1818
PATTERN
1919

20-
def_node_matcher :locals_key?, <<-PATTERN
21-
(pair (sym {
22-
:locals
23-
}) $_)
24-
PATTERN
25-
2620
def_node_matcher :partial_key?, <<-PATTERN
2721
(pair (sym {
2822
:file
@@ -32,10 +26,6 @@ class RailsViewRenderLiteral < Cop
3226
}) $_)
3327
PATTERN
3428

35-
def hash_with_literal_keys?(hash)
36-
hash.pairs.all? { |pair| literal?(pair.key) }
37-
end
38-
3929
def on_send(node)
4030
return unless render?(node)
4131

lib/rubocop/cop/github/render_literal_helpers.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,14 @@ module RenderLiteralHelpers
3636
(send nil? {:render :render_to_string} (send _ :with_collection ...) ...)
3737
PATTERN
3838

39+
def_node_matcher :locals_key?, <<-PATTERN
40+
(pair (sym :locals) $_)
41+
PATTERN
42+
43+
def hash_with_literal_keys?(hash)
44+
hash.pairs.all? { |pair| literal?(pair.key) }
45+
end
46+
3947
def render_view_component?(node)
4048
render_view_component_instance?(node) ||
4149
render_view_component_collection?(node)

test/test_rails_controller_render_literal.rb

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,4 +393,65 @@ def index
393393
assert_equal 1, cop.offenses.count
394394
assert_equal "render must be used with a string literal or an instance of a Class", cop.offenses[0].message
395395
end
396+
397+
def test_render_shorthand_static_locals_no_offsense
398+
investigate cop, <<-RUBY, "app/controllers/products_controller.rb"
399+
class ProductsController < ActionController::Base
400+
def index
401+
render "products/index", locals: { product: product }
402+
end
403+
end
404+
RUBY
405+
406+
assert_equal 0, cop.offenses.count
407+
end
408+
409+
def test_render_partial_static_locals_no_offsense
410+
investigate cop, <<-RUBY, "app/controllers/products_controller.rb"
411+
class ProductsController < ActionController::Base
412+
def index
413+
render partial: "products/index", locals: { product: product }
414+
end
415+
end
416+
RUBY
417+
418+
assert_equal 0, cop.offenses.count
419+
end
420+
421+
def test_render_literal_dynamic_options_offense
422+
investigate cop, <<-RUBY, "app/controllers/products_controller.rb"
423+
class ProductsController < ActionController::Base
424+
def index
425+
render "products/product", options
426+
end
427+
end
428+
RUBY
429+
430+
assert_equal 1, cop.offenses.count
431+
end
432+
433+
def test_render_literal_dynamic_locals_offense
434+
investigate cop, <<-RUBY, "app/controllers/products_controller.rb"
435+
class ProductsController < ActionController::Base
436+
def index
437+
render "products/product", locals: locals
438+
end
439+
end
440+
RUBY
441+
442+
assert_equal 1, cop.offenses.count
443+
end
444+
445+
446+
def test_render_literal_dynamic_local_key_offense
447+
investigate cop, <<-RUBY, "app/controllers/products_controller.rb"
448+
class ProductsController < ActionController::Base
449+
def index
450+
render "products/product", locals: { product_key => product }
451+
end
452+
end
453+
RUBY
454+
455+
assert_equal 1, cop.offenses.count
456+
end
396457
end

0 commit comments

Comments
 (0)