Ruby and Rails with Style

Based on Bozidar Batsov's "Ruby style guide"

Curly braces

# good - space after { and before }
{ one: 1, two: 2 }

# good - no space after { and before }
{one: 1, two: 2}

Use spaces around the = operator when assigning default values to method parameters

# bad
def some_method(arg1=:default, arg2=nil, arg3=[])
  # do something...
end

# good
def some_method(arg1 = :default, arg2 = nil, arg3 = [])
  # do something...
end

Multi-line method chaining

Two options

Option one

# bad - need to consult first line to 
# understand second line
one.two.three.
  four

# good - it's immediately clear what's 
# going on the second line
one.two.three
  .four

Option two

# bad - need to read ahead to the second line 
# to know that the chain continues
one.two.three
  .four

# good - it's immediately clear that the 
# expression continues beyond the first line
one.two.three.
  four

Use :: only to reference constants(this includes classes and modules) and constructors (likeArray() or Nokogiri::HTML()). Do not use :: for regular method invocation.

# bad
SomeClass::some_method
some_object::some_method

# good
SomeClass.some_method
some_object.some_method
SomeModule::SomeClass::SOME_CONST
SomeModule::SomeClass()

Use def with parentheses when there are parameters. Omit the parentheses when the method doesn't accept any parameters.

# bad
def some_method()
 # body omitted
end

# good
def some_method
 # body omitted
end
# bad
def some_method_with_parameters param1, param2
 # body omitted
end

# good
def some_method_with_parameters(param1, param2)
 # body omitted
end

Leverage the fact that if and case are expressions which return a result. 

# bad
if condition
  result = x
else
  result = y
end

# good
result =
  if condition
    x
  else
    y
  end

Logical operators

  •  Use ! instead of not
  •  The and and or keywords are banned. It's just not worth it. Always use && and || instead.

Favor modifier if/unless usage when you have a single-line body. Another good alternative is the usage of control flow &&/||

# bad
if some_condition
  do_something
end

# good
do_something if some_condition

# another good option
some_condition && do_something

Do not use unless with else. Rewrite these with the positive case first.

# bad
unless success?
  puts 'failure'
else
  puts 'success'
end

# good
if success?
  puts 'success'
else
  puts 'failure'
end

Omit the outer braces around an implicit options hash.

# bad
user.set({ name: 'John', age: 45, permissions: { read: true } })

# good
user.set(name: 'John', age: 45, permissions: { read: true })

Omit parentheses for method calls with no arguments.

# bad
Kernel.exit!()
2.even?()
fork()
'test'.upcase()
# good
Kernel.exit!
2.even?
fork
'test'.upcase

Do not omit otherwise, especially when method returns value

# bad
array.delete hash.fetch :foo

# good
array.delete(hash.fetch(:foo))

# bad
result = calculate array, start_point, steps

# good
result = calculate(array, start_point, steps)

Don't use the return value of = (an assignment) in conditional expressions unless the assignment is wrapped in parentheses.

Subtitle

# bad (+ a warning)
if v = array.grep(/foo/)
  do_something(v)
  ...
end

# good (MRI would still complain, but RuboCop won't)
if (v = array.grep(/foo/))
  do_something(v)
  ...
end

# good
v = array.grep(/foo/)
if v
  do_something(v)
  ...
end

Use a consistent structure in your class definitions.

  1. includes and extends
  2. inner classes
  3. constants
  4. attribute macros
  5. other macros
  6. public class methods
  7. public instance methods
  8. protected methods
  9. private methods
class Person
  # extend and include go first
  extend SomeModule
  include AnotherModule

  # inner classes
  CustomErrorKlass = Class.new(StandardError)

  # constants are next
  SOME_CONSTANT = 20

  # afterwards we have attribute macros
  attr_reader :name

  # followed by other macros (if any)
  validates :name

  # public class methods are next in line
  def self.some_method
  end

  # followed by public instance methods
  def some_method
  end

  # protected and private methods are grouped near the end
  protected

  def some_protected_method
  end

  private

  def some_private_method
  end
end

Rails, in short

Each controller action should (ideally) invoke only one method other than an initial find or new.

Share no more than two instance variables between a controller and a view.

Always use the new "sexy" validations.

# bad
validates_presence_of :email

# good
validates :email, presence: true

Enforce foreign-key constraints.

Don't use model classes in migrations. The model classes are constantly evolving and at some point in the future migrations that used to work might stop, because of changes in the models used.

Miscellanea

Avoid needless metaprogramming. 

 Avoid methods longer than 10 LOC (lines of code). Ideally, most methods will be shorter than 5 LOC. Empty lines do not contribute to the relevant LOC.

Use common sense. 

Ruby and Rails with Style

By katafrakt

Ruby and Rails with Style

  • 1,202