Parameters should be whitelisted for mass assignment Open
@push_notification_params = params.require(:push_notification).permit!
- Read upRead up
- Exclude checks
Mass assignment is a feature of Rails which allows an application to create a record from the values of a hash.
Example:
User.new(params[:user])
Unfortunately, if there is a user field called admin
which controls administrator access, now any user can make themselves an administrator.
attr_accessible
and attr_protected
can be used to limit mass assignment. However, Brakeman will warn unless attr_accessible
is used, or mass assignment is completely disabled.
There are two different mass assignment warnings which can arise. The first is when mass assignment actually occurs, such as the example above. This results in a warning like
Unprotected mass assignment near line 61: User.new(params[:user])
The other warning is raised whenever a model is found which does not use attr_accessible
. This produces generic warnings like
Mass assignment is not restricted using attr_accessible
with a list of affected models.
In Rails 3.1 and newer, mass assignment can easily be disabled:
config.active_record.whitelist_attributes = true
Unfortunately, it can also easily be bypassed:
User.new(params[:user], :without_protection => true)
Brakeman will warn on uses of without_protection
.
Method has too many lines. [11/10] Open
def create
query = create_params
begin
results = @smart_village.query query
rescue Graphlient::Errors::GraphQLError => e
- Read upRead up
- Exclude checks
This cop checks if the length of a method exceeds some maximum value. Comment lines can optionally be ignored. The maximum allowed length is configurable.
PushNotificationsController#create has approx 9 statements Open
def create
- Read upRead up
- Exclude checks
A method with Too Many Statements
is any method that has a large number of lines.
Too Many Statements
warns about any method that has more than 5 statements. Reek's smell detector for Too Many Statements
counts +1 for every simple statement in a method and +1 for every statement within a control structure (if
, else
, case
, when
, for
, while
, until
, begin
, rescue
) but it doesn't count the control structure itself.
So the following method would score +6 in Reek's statement-counting algorithm:
def parse(arg, argv, &error)
if !(val = arg) and (argv.empty? or /\A-/ =~ (val = argv[0]))
return nil, block, nil # +1
end
opt = (val = parse_arg(val, &error))[1] # +2
val = conv_arg(*val) # +3
if opt and !arg
argv.shift # +4
else
val[0] = nil # +5
end
val # +6
end
(You might argue that the two assigments within the first @if@ should count as statements, and that perhaps the nested assignment should count as +2.)
PushNotificationsController has no descriptive comment Open
class PushNotificationsController < ApplicationController
- Read upRead up
- Exclude checks
Classes and modules are the units of reuse and release. It is therefore considered good practice to annotate every class and module with a brief comment outlining its responsibilities.
Example
Given
class Dummy
# Do things...
end
Reek would emit the following warning:
test.rb -- 1 warning:
[1]:Dummy has no descriptive comment (IrresponsibleModule)
Fixing this is simple - just an explaining comment:
# The Dummy class is responsible for ...
class Dummy
# Do things...
end
PushNotificationsController assumes too much for instance variable '@push_notification_params' Open
class PushNotificationsController < ApplicationController
- Read upRead up
- Exclude checks
Classes should not assume that instance variables are set or present outside of the current class definition.
Good:
class Foo
def initialize
@bar = :foo
end
def foo?
@bar == :foo
end
end
Good as well:
class Foo
def foo?
bar == :foo
end
def bar
@bar ||= :foo
end
end
Bad:
class Foo
def go_foo!
@bar = :foo
end
def foo?
@bar == :foo
end
end
Example
Running Reek on:
class Dummy
def test
@ivar
end
end
would report:
[1]:InstanceVariableAssumption: Dummy assumes too much for instance variable @ivar
Note that this example would trigger this smell warning as well:
class Parent
def initialize(omg)
@omg = omg
end
end
class Child < Parent
def foo
@omg
end
end
The way to address the smell warning is that you should create an attr_reader
to use @omg
in the subclass and not access @omg
directly like this:
class Parent
attr_reader :omg
def initialize(omg)
@omg = omg
end
end
class Child < Parent
def foo
omg
end
end
Directly accessing instance variables is considered a smell because it breaks encapsulation and makes it harder to reason about code.
If you don't want to expose those methods as public API just make them private like this:
class Parent
def initialize(omg)
@omg = omg
end
private
attr_reader :omg
end
class Child < Parent
def foo
omg
end
end
Current Support in Reek
An instance variable must:
- be set in the constructor
- or be accessed through a method with lazy initialization / memoization.
If not, Instance Variable Assumption will be reported.
PushNotificationsController assumes too much for instance variable '@smart_village' Open
class PushNotificationsController < ApplicationController
- Read upRead up
- Exclude checks
Classes should not assume that instance variables are set or present outside of the current class definition.
Good:
class Foo
def initialize
@bar = :foo
end
def foo?
@bar == :foo
end
end
Good as well:
class Foo
def foo?
bar == :foo
end
def bar
@bar ||= :foo
end
end
Bad:
class Foo
def go_foo!
@bar = :foo
end
def foo?
@bar == :foo
end
end
Example
Running Reek on:
class Dummy
def test
@ivar
end
end
would report:
[1]:InstanceVariableAssumption: Dummy assumes too much for instance variable @ivar
Note that this example would trigger this smell warning as well:
class Parent
def initialize(omg)
@omg = omg
end
end
class Child < Parent
def foo
@omg
end
end
The way to address the smell warning is that you should create an attr_reader
to use @omg
in the subclass and not access @omg
directly like this:
class Parent
attr_reader :omg
def initialize(omg)
@omg = omg
end
end
class Child < Parent
def foo
omg
end
end
Directly accessing instance variables is considered a smell because it breaks encapsulation and makes it harder to reason about code.
If you don't want to expose those methods as public API just make them private like this:
class Parent
def initialize(omg)
@omg = omg
end
private
attr_reader :omg
end
class Child < Parent
def foo
omg
end
end
Current Support in Reek
An instance variable must:
- be set in the constructor
- or be accessed through a method with lazy initialization / memoization.
If not, Instance Variable Assumption will be reported.
PushNotificationsController#new_push_notification doesn't depend on instance state (maybe move it to another class?) Open
def new_push_notification
- Read upRead up
- Exclude checks
A Utility Function is any instance method that has no dependency on the state of the instance.
PushNotificationsController#create has the variable name 'e' Open
rescue Graphlient::Errors::GraphQLError => e
- Read upRead up
- Exclude checks
An Uncommunicative Variable Name
is a variable name that doesn't communicate its intent well enough.
Poor names make it hard for the reader to build a mental picture of what's going on in the code. They can also be mis-interpreted; and they hurt the flow of reading, because the reader must slow down to interpret the names.
Useless assignment to variable - results
. Open
results = @smart_village.query query
- Read upRead up
- Exclude checks
This cop checks for every useless assignment to local variable in every
scope.
The basic idea for this cop was from the warning of ruby -cw
:
assigned but unused variable - foo
Currently this cop has advanced logic that detects unreferenced reassignments and properly handles varied cases such as branch, loop, rescue, ensure, etc.
Example:
# bad
def some_method
some_var = 1
do_something
end
Example:
# good
def some_method
some_var = 1
do_something(some_var)
end
Missing top-level class documentation comment. Open
class PushNotificationsController < ApplicationController
- Read upRead up
- Exclude checks
This cop checks for missing top-level documentation of classes and modules. Classes with no body are exempt from the check and so are namespace modules - modules that have nothing in their bodies except classes, other modules, or constant definitions.
The documentation requirement is annulled if the class or module has a "#:nodoc:" comment next to it. Likewise, "#:nodoc: all" does the same for all its children.
Example:
# bad
class Person
# ...
end
# good
# Description/Explanation of Person class
class Person
# ...
end