Giter Site home page Giter Site logo

rubocop / rubocop-rails Goto Github PK

View Code? Open in Web Editor NEW
782.0 17.0 244.0 28.12 MB

A RuboCop extension focused on enforcing Rails best practices and coding conventions.

Home Page: https://docs.rubocop.org/rubocop-rails

License: MIT License

Ruby 99.99% Shell 0.01%
ruby rubocop linter static-code-analysis code-formatter rails hacktoberfest

rubocop-rails's Introduction

RuboCop Logo


Ruby Style Guide Gem Version CircleCI Status Actions Status Test Coverage Maintainability Discord

Role models are important.
-- Officer Alex J. Murphy / RoboCop

RuboCop is a Ruby static code analyzer (a.k.a. linter) and code formatter. Out of the box it will enforce many of the guidelines outlined in the community Ruby Style Guide. Apart from reporting the problems discovered in your code, RuboCop can also automatically fix many of them for you.

RuboCop is extremely flexible and most aspects of its behavior can be tweaked via various configuration options.


Patreon OpenCollective OpenCollective Tidelift

Working on RuboCop is often fun, but it also requires a great deal of time and energy.

Please consider financially supporting its ongoing development.

Installation

RuboCop's installation is pretty standard:

$ gem install rubocop

If you'd rather install RuboCop using bundler, add a line for it in your Gemfile (but set the require option to false, as it is a standalone tool):

gem 'rubocop', require: false

RuboCop is stable between minor versions, both in terms of API and cop configuration. We aim to ease the maintenance of RuboCop extensions and the upgrades between RuboCop releases. All big changes are reserved for major releases. To prevent an unwanted RuboCop update you might want to use a conservative version lock in your Gemfile:

gem 'rubocop', '~> 1.63', require: false

See our versioning policy for further details.

Quickstart

Just type rubocop in a Ruby project's folder and watch the magic happen.

$ cd my/cool/ruby/project
$ rubocop

You can also use this magic in your favorite editor with RuboCop's built-in LSP server.

Documentation

You can read a lot more about RuboCop in its official docs.

Compatibility

RuboCop officially supports the following runtime Ruby implementations:

  • MRI 2.7+
  • JRuby 9.4+

Targets Ruby 2.0+ code analysis.

See the compatibility documentation for further details.

Readme Badge

If you use RuboCop in your project, you can include one of these badges in your readme to let people know that your code is written following the community Ruby Style Guide.

Ruby Style Guide

Ruby Style Guide

Here are the Markdown snippets for the two badges:

[![Ruby Style Guide](https://img.shields.io/badge/code_style-rubocop-brightgreen.svg)](https://github.com/rubocop/rubocop)

[![Ruby Style Guide](https://img.shields.io/badge/code_style-community-brightgreen.svg)](https://rubystyle.guide)

Team

Here's a list of RuboCop's core developers:

See the team page for more details.

Logo

RuboCop's logo was created by Dimiter Petrov. You can find the logo in various formats here.

The logo is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.

Contributors

Here's a list of all the people who have contributed to the development of RuboCop.

I'm extremely grateful to each and every one of them!

If you'd like to contribute to RuboCop, please take the time to go through our short contribution guidelines.

Converting more of the Ruby Style Guide into RuboCop cops is our top priority right now. Writing a new cop is a great way to dive into RuboCop!

Of course, bug reports and suggestions for improvements are always welcome. GitHub pull requests are even better! :-)

Funding

While RuboCop is free software and will always be, the project would benefit immensely from some funding. Raising a monthly budget of a couple of thousand dollars would make it possible to pay people to work on certain complex features, fund other development related stuff (e.g. hardware, conference trips) and so on. Raising a monthly budget of over $5000 would open the possibility of someone working full-time on the project which would speed up the pace of development significantly.

We welcome both individual and corporate sponsors! We also offer a wide array of funding channels to account for your preferences (although currently Open Collective is our preferred funding platform).

If you're working in a company that's making significant use of RuboCop we'd appreciate it if you suggest to your company to become a RuboCop sponsor.

You can support the development of RuboCop via GitHub Sponsors, Patreon, PayPal, Open Collective and Tidelift .

Note: If doing a sponsorship in the form of donation is problematic for your company from an accounting standpoint, we'd recommend the use of Tidelift, where you can get a support-like subscription instead.

Open Collective Backers

Support us with a monthly donation and help us continue our activities. [Become a backer]

Open Collective Sponsors

Become a sponsor and get your logo on our README on GitHub with a link to your site. [Become a sponsor]

Changelog

RuboCop's changelog is available here.

Copyright

Copyright (c) 2012-2024 Bozhidar Batsov. See LICENSE.txt for further details.

rubocop-rails's People

Contributors

alexdowad avatar andyw8 avatar backus avatar bbatsov avatar bquorning avatar drenmi avatar dvandersluis avatar earlopain avatar eugeneius avatar fatkodima avatar garettarrowood avatar geniou avatar hoshinotsuyoshi avatar jonas054 avatar koic avatar lumeet avatar masato-bkn avatar maxjacobson avatar palkan avatar pirj avatar pocke avatar quinnharris avatar r7kamura avatar rrosenblum avatar sinsoku avatar sunny avatar tejasbubane avatar wata727 avatar ydah avatar yujinakayama avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rubocop-rails's Issues

Rails/EnumNotNullColumn - New idea for an enum rule

I just realized that I wasn't setting a NOT NULL constraint for any of my enum columns. This came to my attention when my API test returned null for one of my state columns, and I realized that null was never a valid value for this particular state column. I think it's a much better practice to define an integer value that represents nothing, e.g. none: 0, if that's necessary. This way you can also control the string value that represents 0, and the ActiveRecord helper methods are consistent when you use a _prefix. E.g. you can call model.foo_type_none? instead of !model.foo_type?.

Technically nil is a valid value for an enum column, and it just means that the column hasn't been defined yet. But I think that this will lead to errors more often than being a useful default.

My idea is to scan the Rails model source code for enum calls and parse out the attribute. It would find the following enums:

class Model < ApplicationRecord
  enum state: {
    pending: 0,
    complete: 1,
  }

  enum :foo => %w[bar baz]
  enum 'bar' => %w[hello world]
  enum "baz" => %w[one last example]
end

Then it would raise 4 errors for the following migration:

class CreateModels < ActiveRecord::Migration[5.2]
  def change
    create_table :models do |t|
      t.integer :state, default: 0
      t.integer :foo, default: 0
      t.integer :bar, default: 0
      t.integer :baz, default: 0
    end
  end
end

It should say that all of the integer columns must be written as:

      t.integer :state, default: 0, null: false
      t.integer :foo, default: 0, null: false
      t.integer :bar, default: 0, null: false
      t.integer :baz, default: 0, null: false

This would have been very helpful for me, because I forgot that integers can still be set to nil, even if I'm setting the default to 0. It wouldn't need handle every single cases (custom DSLs, or calls to add_column and change_column_null), but it would be nice to catch 99% of these cases.

CircleCI build for PRs

I noticed on #38 that the CircleCI build wasn’t running. Checking our Circle config I found that it was set to not build PRs from forked repositories. I’ve now enabled that setting, and I assume new pull requests (and new commits to existing PRs) will trigger a build.

/cc @koic

Rails/BulkChangeTable and remove_column

This code would trigger Rails/BulkChangeTable

class ChangeACoupleOfColumnsInThing < ActiveRecord::Migration[5.2]
  def change
    remove_column :things, :column_one, :boolean
    add_column    :things, :column_two, :string, null: false, default: ''
  end
end

The problem is that this:

class ChangeACoupleOfColumnsInThing < ActiveRecord::Migration[5.2]
  def change
    change_table :sellers, bulk: true do |t|
      t.remove :column_one, :boolean
      t.column :column_two, :string, null: false, default: ''
    end
  end
end

Will raise RailsReversibleMigration.

Version:

$ rubocop -V
0.57.2

Rails/DynamicFindBy issue with Gem::Specification.find_by_name

The analyzer should not complain about Gem::Specification.find_by_name as this is not an ActiveRecord model and so using find_by_name is correct:

Offenses:

spec/features/admin/orders/adding_line_items_spec.rb:5:11: C: Rails/DynamicFindBy: Use find_by instead of dynamic find_by_name.
gem_dir = Gem::Specification.find_by_name("solidus_backend").gem_dir
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

1 file inspected, 1 offense detected

This is an old issue from the original Rubocop repo: rubocop/rubocop#4967

RuboCop version

Include the output of rubocop -V or bundle exec rubocop -V if using Bundler. Here's an example:

$ [bundle exec] rubocop -V
0.68.1 (using Parser 2.6.3.0, running on ruby 2.5.0 x86_64-darwin17)

Rails/HasManyOrHasOneDependent with paranoia gem

Moved from rubocop/rubocop#5285

Hi!

Do you have any suggestions how to use gems providing soft-delete (like paranoia) with HasManyOrHasOneDependent cop: I think it's usual to not provide dependent option to has_many when parent is soft-deletable. Is it supposed just to use rubocop:disable for offences in such cases?

RuboCop version

$ rubocop -V
0.52.0 (using Parser 2.4.0.2, running on ruby 2.4.1 x86_64-darwin16)

An error occurred while Rails/HttpStatus cop was inspecting a controller

When running newest rubocop on our rails project, we get this error for each and every controller in the project. Here the stack trace:

An error occurred while Rails/HttpStatus cop was inspecting /home/testuser/inp/frontend/app/controllers/user/events_controller.rb:42:15.
uninitialized constant Rack
Did you mean?  Racc
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/cop/rails/http_status.rb:131:in `custom_http_status_code?'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/cop/rails/http_status.rb:104:in `offensive?'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/cop/rails/http_status.rb:64:in `block in on_send'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/cop/rails/http_status.rb:46:in `http_status'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/cop/rails/http_status.rb:62:in `on_send'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/cop/commissioner.rb:44:in `block (2 levels) in on_send'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/cop/commissioner.rb:109:in `with_cop_error_handling'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/cop/commissioner.rb:43:in `block in on_send'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/cop/commissioner.rb:42:in `each'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/cop/commissioner.rb:42:in `on_send'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/ast/traversal.rb:49:in `block in on_return'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/ast/traversal.rb:49:in `each'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/ast/traversal.rb:49:in `on_return'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/cop/commissioner.rb:48:in `on_return'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/ast/traversal.rb:159:in `block in on_case'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/ast/traversal.rb:158:in `each'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/ast/traversal.rb:158:in `on_case'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/cop/commissioner.rb:48:in `on_resbody'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/ast/traversal.rb:159:in `block in on_case'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/ast/traversal.rb:158:in `each'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/ast/traversal.rb:158:in `on_case'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/cop/commissioner.rb:48:in `on_rescue'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/ast/traversal.rb:49:in `block in on_kwbegin'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/ast/traversal.rb:49:in `each'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/ast/traversal.rb:49:in `on_kwbegin'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/cop/commissioner.rb:48:in `on_kwbegin'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/ast/traversal.rb:49:in `block in on_begin'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/ast/traversal.rb:49:in `each'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/ast/traversal.rb:49:in `on_begin'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/cop/commissioner.rb:48:in `on_begin'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/ast/traversal.rb:95:in `on_def'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/cop/commissioner.rb:48:in `on_def'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/ast/traversal.rb:49:in `block in on_begin'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/ast/traversal.rb:49:in `each'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/ast/traversal.rb:49:in `on_begin'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/cop/commissioner.rb:48:in `on_begin'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/ast/traversal.rb:88:in `on_class'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/cop/commissioner.rb:48:in `on_class'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/ast/traversal.rb:141:in `on_while'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/cop/commissioner.rb:48:in `on_module'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/ast/traversal.rb:12:in `walk'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/cop/commissioner.rb:60:in `investigate'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/cop/team.rb:114:in `investigate'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/cop/team.rb:102:in `offenses'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/cop/team.rb:44:in `inspect_file'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/runner.rb:259:in `inspect_file'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/runner.rb:206:in `block in do_inspection_loop'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/runner.rb:238:in `block in iterate_until_no_changes'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/runner.rb:231:in `loop'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/runner.rb:231:in `iterate_until_no_changes'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/runner.rb:202:in `do_inspection_loop'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/runner.rb:111:in `block in file_offenses'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/runner.rb:121:in `file_offense_cache'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/runner.rb:109:in `file_offenses'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/runner.rb:100:in `process_file'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/runner.rb:78:in `block in each_inspected_file'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/runner.rb:75:in `each'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/runner.rb:75:in `reduce'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/runner.rb:75:in `each_inspected_file'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/runner.rb:67:in `inspect_files'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/runner.rb:39:in `run'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/cli.rb:156:in `execute_runner'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/cli.rb:84:in `execute_runners'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/lib/rubocop/cli.rb:41:in `run'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/bin/rubocop:13:in `block in <top (required)>'
/home/testuser/.rvm/rubies/ruby-2.3.4/lib/ruby/2.3.0/benchmark.rb:308:in `realtime'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/gems/rubocop-0.54.0/bin/rubocop:12:in `<top (required)>'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/bin/rubocop:22:in `load'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/bin/rubocop:22:in `<main>'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/bin/ruby_executable_hooks:15:in `eval'
/home/testuser/.rvm/gems/ruby-2.3.4@my-gemset/bin/ruby_executable_hooks:15:in `<main>'

I cannot share the source code of the project itself, but I can provide details if necessary.

I should mention that our directory structure looks like this:

/
├── Gemfile # rubocop dependency defined here
├── Gemfile.lock
├── .rubocop_todo.yml
├── .rubocop.yml # rubocop config with some configured rules
├── .ruby-gemset
├── .ruby-version
├── frontend # frontend rails application which rubocop is executed within
│   ├── Gemfile # rails dependencies
│   ├── Gemfile.lock
│   ├── .rubocop.yml # rubocop config inheriting from config from upper folder with rails checks activated

I get the errors when running rubocop from within the rails_app folder. TargetRailsVersion is 4.2.

RuboCop version

0.54.0 (using Parser 2.5.0.5, running on ruby 2.3.4 x86_64-linux)

Rails/TimeZone is corrected to Time.zone.new which raises NoMethodError

Expected behavior

Time.new to Time.zone.local or something.

Actual behavior

C: [Corrected] Rails/TimeZone: Do not use Time.new without zone. Use one of Time.zone.local, Time.current, Time.new.in_time_zone, Time.new.utc, Time.new.getlocal, Time.new.xmlschema, Time.new.iso8601, Time.new.jisx0301, Time.new.rfc3339, Time.new.httpdate, Time.new.to_i, Time.new.to_f instead.

Time.new(2019)

is auto corrected to

Time.zone.new(2019)

Steps to reproduce the problem

Auto correct in minimal environment:

% cat .rubocop.yml
require:
- rubocop-rails
% cat now.rb
Time.new(2019)
% rubocop -a now.rb
Inspecting 1 file
C

Offenses:

now.rb:1:1: C: [Corrected] Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
Time.new(2019)
^
now.rb:1:6: C: [Corrected] Rails/TimeZone: Do not use Time.new without zone. Use one of Time.zone.local, Time.current, Time.new.in_time_zone, Time.new.utc, Time.new.getlocal, Time.new.xmlschema, Time.new.iso8601, Time.new.jisx0301, Time.new.rfc3339, Time.new.httpdate, Time.new.to_i, Time.new.to_f instead.
Time.new(2019)
     ^^^

1 file inspected, 2 offenses detected, 2 offenses corrected
% cat now.rb
# frozen_string_literal: true

Time.zone.new(2019)

In rails console:

Loading development environment (Rails 5.2.3)
irb(main):001:0> Time.new(2019)
=> 2019-01-01 00:00:00 +0900
irb(main):002:0> Time.zone.new(2019)
Traceback (most recent call last):
        1: from (irb):2
NoMethodError (undefined method `new' for #<ActiveSupport::TimeZone:0x00007fe02454b2d8>)
Did you mean?  now

RuboCop version

0.72.0 (using Parser 2.6.3.0, running on ruby 2.6.3 x86_64-darwin18)

and rubocop-rails (2.1.0)

[Proposal] A new cop to prefer `fetch` for Rails.application.secrets

Rails.application.secrets.foo returns nil if the entry does not exist. However, accessing a missing entry is likely to a typo.

Fortunately, it has fetch() method that raises errors in a missing entry, so it's a good idea to prefer fetch() instead of the use of getter.

e.g.

# good
foo = Rails.application.secrets.fetch(:foo)

# bad
foo = Rails.application.secrets.foo

Rails cops: referer vs referrer

Rails supports both request.referer and request.referrer, and after perusing our codebase we discovered that we're using both. It would be great to have a cop to enforce one or the other for the sake of consistency.

Feature request - add a cop to detect missing `:environment` dependencies in rake tasks

I'm always frustrated when I commit a rake task to my rails project and I forget the :environment dependency. For example:

task :fix_something do # should be `task fix_something: :environment do`
   User.where(...).find_each { |u| # fix the user }
end

This runs just fine in my dev environment, probably because spring is running and just forks off a process where the whole rails env is loaded. So I push to production. Later on production

rake fix_something
rake aborted!
NameError: uninitialized constant User

:rage4:

Describe the solution you'd like

I would like a rails cop that warns if you write a rake task without an environment dependency. It is rarely what you want. It is also easy to miss in code reviews.

Do not use Date.current in rails unsuspected error

I see Do not use Date.current without zone. Use Time.zone.today instead in my rails project.
But It has already overrided in activesupport.
Look here https://www.omniref.com/ruby/gems/activesupport/4.2.0/symbols/Date/current?d=372865379&n=0#

lib/active_support/core_ext/date/calculations.rb

    # Returns Time.zone.today when <tt>Time.zone</tt> or <tt>config.time_zone</tt> are set, otherwise just returns Date.today.
    def current
      ::Time.zone ? ::Time.zone.today : ::Date.today
    end

How is possible? Am I wrong or rubocop?

Cop for detecting consecutive `after_commit` hooks for the same model

Problem

There can only be one after_commit hook defined for a model. This, however, is pretty confusing in the light of the on: option and its abbreviations (after_create_commit, after_update_commit and after_destroy_commit). For example, the following examples all result in a single after_commit hook being defined:

after_create_commit :log_create
after_update_commit :log_update
after_commit :callback, :on => :create
after_commit :callback, :on => :update, :if => :condition

See also:

Interestingly enough, the following works

after_create_commit -> { foo }
after_update_commit -> { foo }

See also:

So the cop could recommend to only use this format.

Describe the solution you'd like

I'd like rubocop to be able to detect this scenario and only allow for one after_commit and its abbreviations per model.

Suggested cop: Avoid instance variables in helpers

I was reminded of this principal when reading Noel Rappin's book, Rails 5 Test Prescriptions:

If for some reason your helper method requires a specific instance variable to be set, cut that out immediately; it’s a bad idea.

Rails/SaveBang does not account for control flow

Expected behavior

I expect the following code to be allowed by rubocop, because the value of the create method is (possibly) returned by the function, and AllowImplicitReturn is true by default.

def find_or_create(**opts)
  find(**opts) || create(**opts)
end

Actual behavior

The Rails/SaveBang cop reports that I should use create! instead of create.

my_model.rb:3:21: C: Rails/SaveBang: create returns a model which is always truthy.
    find(**opts) || create(**opts)
                    ^^^^^^

Steps to reproduce the problem

Assuming you have Rails cops enabled. Save the following file and run rubocop filename.rb.

class MyModel < ActiveRecord::Model
  def find_or_create(**opts)
    find(**opts) || create(**opts)
  end
end

RuboCop version

0.68.1 (using Parser 2.6.3.0, running on ruby 2.6.1 x86_64-linux)

Not reporting offenses for Rails generated files by default

Is your feature request related to a problem? Please describe.

I'd like RuboCop Rails gem provide a way to ignore offenses for files generated by Rails.

Steps to reproduce

Created a rubocop_rails_demo repository which just contains a Rails application running 6.0.0.rc1. It requires Ruby 2.6.3.

$ git clone [email protected]:yahonda/rubocop_rails_demo.git
$ cd rubocop_rails_demo.git
$ bundle install
$ bundle exec rubocop

Expected behavior

It does not report any offenses since these all of these files are generated by Rails, not application developers

Actual behavior

It reports 40 files inspected, 170 offenses detected.

$ bundle exec rubocop
Inspecting 40 files
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC

Offenses:

config.ru:1:1: C: Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
# This file is used by Rack-based servers to start the application.
^
Gemfile:1:1: C: Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
source 'https://rubygems.org'
^
Gemfile:32:81: C: Metrics/LineLength: Line is too long. [83/80]
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
                                                                                ^^^
Gemfile:33:28: C: Style/SymbolArray: Use %i or %I for an array of symbols.
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^
Gemfile:37:81: C: Metrics/LineLength: Line is too long. [98/80]
  # Access an interactive console on exception pages or by calling 'console' anywhere in the code.
                                                                                ^^^^^^^^^^^^^^^^^^
Gemfile:39:3: C: Bundler/OrderedGems: Gems should be sorted in an alphabetical order within their section of the Gemfile. Gem listen should appear before web-console.
  gem 'listen', '>= 3.0.5', '< 3.2'
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Gemfile:40:81: C: Metrics/LineLength: Line is too long. [130/80]
  # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
                                                                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Gemfile:54:31: C: Style/SymbolArray: Use %i or %I for an array of symbols.
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Rakefile:1:1: C: Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
# Add your own tasks in files placed in lib/tasks ending in .rake,
^
Rakefile:2:81: C: Metrics/LineLength: Line is too long. [90/80]
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
                                                                                ^^^^^^^^^^
app/channels/application_cable/channel.rb:1:1: C: Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
module ApplicationCable
^
app/channels/application_cable/connection.rb:1:1: C: Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
module ApplicationCable
^
app/controllers/application_controller.rb:1:1: C: Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
class ApplicationController < ActionController::Base
^
app/helpers/application_helper.rb:1:1: C: Style/Documentation: Missing top-level module documentation comment.
module ApplicationHelper
^^^^^^
app/helpers/application_helper.rb:1:1: C: Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
module ApplicationHelper
^
app/jobs/application_job.rb:1:1: C: Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
class ApplicationJob < ActiveJob::Base
^
app/jobs/application_job.rb:5:81: C: Metrics/LineLength: Line is too long. [82/80]
  # Most jobs are safe to ignore if the underlying records are no longer available
                                                                                ^^
app/mailers/application_mailer.rb:1:1: C: Style/Documentation: Missing top-level class documentation comment.
class ApplicationMailer < ActionMailer::Base
^^^^^
app/mailers/application_mailer.rb:1:1: C: Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
class ApplicationMailer < ActionMailer::Base
^
app/models/application_record.rb:1:1: C: Style/Documentation: Missing top-level class documentation comment.
class ApplicationRecord < ActiveRecord::Base
^^^^^
app/models/application_record.rb:1:1: C: Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
class ApplicationRecord < ActiveRecord::Base
^
bin/bundle:11:9: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
require "rubygems"
        ^^^^^^^^^^
bin/bundle:14:5: C: Layout/AccessModifierIndentation: Indent access modifiers like module_function.
    module_function
    ^^^^^^^^^^^^^^^
bin/bundle:17:22: C: Style/SpecialGlobalVars: Prefer $PROGRAM_NAME over $0.
    File.expand_path($0) == File.expand_path(__FILE__)
                     ^^
bin/bundle:21:9: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
    ENV["BUNDLER_VERSION"]
        ^^^^^^^^^^^^^^^^^
bin/bundle:24:3: C: Metrics/CyclomaticComplexity: Cyclomatic complexity for cli_arg_version is too high. [9/6]
  def cli_arg_version ...
  ^^^^^^^^^^^^^^^^^^^
bin/bundle:24:3: C: Metrics/MethodLength: Method has too many lines. [13/10]
  def cli_arg_version ...
  ^^^^^^^^^^^^^^^^^^^
bin/bundle:24:3: C: Metrics/PerceivedComplexity: Perceived complexity for cli_arg_version is too high. [9/7]
  def cli_arg_version ...
  ^^^^^^^^^^^^^^^^^^^
bin/bundle:26:5: C: Layout/EmptyLineAfterGuardClause: Add empty line after guard clause.
    return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update`
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
bin/bundle:26:19: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
    return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update`
                  ^^^^^^^^
bin/bundle:26:54: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
    return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update`
                                                     ^^^
bin/bundle:26:81: C: Metrics/LineLength: Line is too long. [91/80]
    return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update`
                                                                                ^^^^^^^^^^^
bin/bundle:30:81: C: Metrics/LineLength: Line is too long. [94/80]
      if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN
                                                                                ^^^^^^^^^^^^^^
bin/bundle:33:7: C: Layout/EmptyLineAfterGuardClause: Add empty line after guard clause.
      next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
bin/bundle:33:81: C: Metrics/LineLength: Line is too long. [81/80]
      next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/
                                                                                ^
bin/bundle:34:25: C: Style/PerlBackrefs: Avoid the use of Perl-style backrefs.
      bundler_version = $1 || ">= 0.a"
                        ^^
bin/bundle:34:31: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
      bundler_version = $1 || ">= 0.a"
                              ^^^^^^^^
bin/bundle:41:19: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
    gemfile = ENV["BUNDLE_GEMFILE"]
                  ^^^^^^^^^^^^^^^^
bin/bundle:42:23: C: Rails/Present: Use gemfile.present? instead of gemfile && !gemfile.empty?.
    return gemfile if gemfile && !gemfile.empty?
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^
bin/bundle:44:10: C: Style/ExpandPathArguments: Use expand_path('../Gemfile', __dir__) instead of expand_path('../../Gemfile', __FILE__).
    File.expand_path("../../Gemfile", __FILE__)
         ^^^^^^^^^^^
bin/bundle:44:22: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
    File.expand_path("../../Gemfile", __FILE__)
                     ^^^^^^^^^^^^^^^
bin/bundle:50:12: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
      when "gems.rb" then gemfile.sub(/\.rb$/, gemfile)
           ^^^^^^^^^
bin/bundle:57:5: C: Layout/EmptyLineAfterGuardClause: Add empty line after guard clause.
    return unless File.file?(lockfile)
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
bin/bundle:59:5: C: Layout/EmptyLineAfterGuardClause: Add empty line after guard clause.
    return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
bin/bundle:59:81: C: Metrics/LineLength: Line is too long. [101/80]
    return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/
                                                                                ^^^^^^^^^^^^^^^^^^^^^
bin/bundle:71:9: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
    ENV["BUNDLE_GEMFILE"] ||= gemfile
        ^^^^^^^^^^^^^^^^
bin/bundle:77:3: C: Metrics/AbcSize: Assignment Branch Condition size for activate_bundler is too high. [17.35/15]
  def activate_bundler(bundler_version) ...
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
bin/bundle:77:3: C: Metrics/MethodLength: Method has too many lines. [13/10]
  def activate_bundler(bundler_version) ...
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
bin/bundle:78:81: C: Metrics/LineLength: Line is too long. [116/80]
    if Gem::Version.correct?(bundler_version) && Gem::Version.new(bundler_version).release < Gem::Version.new("2.0")
                                                                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
bin/bundle:78:111: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
    if Gem::Version.correct?(bundler_version) && Gem::Version.new(bundler_version).release < Gem::Version.new("2.0")
                                                                                                              ^^^^^
bin/bundle:79:25: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
      bundler_version = "< 2"
                        ^^^^^
bin/bundle:82:11: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
      gem "bundler", bundler_version
          ^^^^^^^^^
bin/bundle:84:5: C: Layout/EmptyLineAfterGuardClause: Add empty line after guard clause.
    return if gem_error.nil?
    ^^^^^^^^^^^^^^^^^^^^^^^^
bin/bundle:86:15: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
      require "bundler/version"
              ^^^^^^^^^^^^^^^^^
bin/bundle:88:5: C: Layout/EmptyLineAfterGuardClause: Add empty line after guard clause.
    return if require_error.nil? && Gem::Requirement.new(bundler_version).satisfied_by?(Gem::Version.new(Bundler::VERSION))
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
bin/bundle:88:81: C: Metrics/LineLength: Line is too long. [123/80]
    return if require_error.nil? && Gem::Requirement.new(bundler_version).satisfied_by?(Gem::Version.new(Bundler::VERSION))
                                                                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
bin/bundle:89:81: C: Metrics/LineLength: Line is too long. [190/80]
    warn "Activating bundler (#{bundler_version}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_version}'`"
                                                                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
bin/bundle:103:1: C: Style/IfUnlessModifier: Favor modifier if usage when having a single-line body. Another good alternative is the usage of control flow &&/||.
if m.invoked_as_script?
^^
bin/bundle:104:21: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
  load Gem.bin_path("bundler", "bundle")
                    ^^^^^^^^^
bin/bundle:104:32: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
  load Gem.bin_path("bundler", "bundle")
                               ^^^^^^^^
bin/rails:1:1: C: Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
#!/usr/bin/env ruby
^
bin/rails:3:13: C: Style/ExpandPathArguments: Use expand_path('spring', __dir__) instead of expand_path('../spring', __FILE__).
  load File.expand_path('../spring', __FILE__)
            ^^^^^^^^^^^
bin/rake:1:1: C: Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
#!/usr/bin/env ruby
^
bin/rake:3:13: C: Style/ExpandPathArguments: Use expand_path('spring', __dir__) instead of expand_path('../spring', __FILE__).
  load File.expand_path('../spring', __FILE__)
            ^^^^^^^^^^^
bin/setup:1:1: C: Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
#!/usr/bin/env ruby
^
bin/setup:12:81: C: Metrics/LineLength: Line is too long. [87/80]
  # This script is a way to setup or update your development environment automatically.
                                                                                ^^^^^^^
bin/setup:13:81: C: Metrics/LineLength: Line is too long. [95/80]
  # This script is idempotent, so that you can run it at anytime and get an expectable outcome.
                                                                                ^^^^^^^^^^^^^^^
bin/spring:1:1: C: Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
#!/usr/bin/env ruby
^
bin/webpack:1:1: C: Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
#!/usr/bin/env ruby
^
bin/webpack:3:5: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development"
    ^^^^^^^^^^^
bin/webpack:3:26: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development"
                         ^^^^^^^^^^
bin/webpack:3:41: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development"
                                        ^^^^^^^^^^^^^
bin/webpack:4:5: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
ENV["NODE_ENV"]  ||= "development"
    ^^^^^^^^^^
bin/webpack:4:22: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
ENV["NODE_ENV"]  ||= "development"
                     ^^^^^^^^^^^^^
bin/webpack:6:9: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
require "pathname"
        ^^^^^^^^^^
bin/webpack:7:5: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
    ^^^^^^^^^^^^^^^^
bin/webpack:7:44: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
                                           ^^^^^^^^^^^^^^^
bin/webpack:8:3: C: Layout/AlignArguments: Align the arguments of a method call if they span more than one line.
  Pathname.new(__FILE__).realpath)
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
bin/webpack:10:9: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
require "rubygems"
        ^^^^^^^^^^
bin/webpack:11:9: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
require "bundler/setup"
        ^^^^^^^^^^^^^^^
bin/webpack:13:9: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
require "webpacker"
        ^^^^^^^^^^^
bin/webpack:14:9: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
require "webpacker/webpack_runner"
        ^^^^^^^^^^^^^^^^^^^^^^^^^^
bin/webpack:16:29: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
APP_ROOT = File.expand_path("..", __dir__)
                            ^^^^
bin/webpack-dev-server:1:1: C: Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
#!/usr/bin/env ruby
^
bin/webpack-dev-server:3:5: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development"
    ^^^^^^^^^^^
bin/webpack-dev-server:3:26: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development"
                         ^^^^^^^^^^
bin/webpack-dev-server:3:41: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development"
                                        ^^^^^^^^^^^^^
bin/webpack-dev-server:4:5: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
ENV["NODE_ENV"]  ||= "development"
    ^^^^^^^^^^
bin/webpack-dev-server:4:22: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
ENV["NODE_ENV"]  ||= "development"
                     ^^^^^^^^^^^^^
bin/webpack-dev-server:6:9: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
require "pathname"
        ^^^^^^^^^^
bin/webpack-dev-server:7:5: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
    ^^^^^^^^^^^^^^^^
bin/webpack-dev-server:7:44: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
                                           ^^^^^^^^^^^^^^^
bin/webpack-dev-server:8:3: C: Layout/AlignArguments: Align the arguments of a method call if they span more than one line.
  Pathname.new(__FILE__).realpath)
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
bin/webpack-dev-server:10:9: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
require "rubygems"
        ^^^^^^^^^^
bin/webpack-dev-server:11:9: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
require "bundler/setup"
        ^^^^^^^^^^^^^^^
bin/webpack-dev-server:13:9: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
require "webpacker"
        ^^^^^^^^^^^
bin/webpack-dev-server:14:9: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
require "webpacker/dev_server_runner"
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
bin/webpack-dev-server:16:29: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
APP_ROOT = File.expand_path("..", __dir__)
                            ^^^^
bin/yarn:1:1: C: Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
#!/usr/bin/env ruby
^
bin/yarn:4:3: C: Style/RedundantBegin: Redundant begin block detected.
  begin
  ^^^^^
bin/yarn:5:10: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
    exec "yarnpkg", *ARGV
         ^^^^^^^^^
bin/yarn:7:5: C: Style/StderrPuts: Use warn instead of $stderr.puts to allow such output to be disabled.
    $stderr.puts "Yarn executable was not detected in the system."
    ^^^^^^^^^^^^
bin/yarn:7:18: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
    $stderr.puts "Yarn executable was not detected in the system."
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
bin/yarn:8:5: C: Style/StderrPuts: Use warn instead of $stderr.puts to allow such output to be disabled.
    $stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install"
    ^^^^^^^^^^^^
bin/yarn:8:18: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
    $stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install"
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
config/application.rb:1:1: C: Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
require_relative 'boot'
^
config/application.rb:10:3: C: Style/Documentation: Missing top-level class documentation comment.
  class Application < Rails::Application
  ^^^^^
config/application.rb:14:81: C: Metrics/LineLength: Line is too long. [82/80]
    # Settings in config/environments/* take precedence over those specified here.
                                                                                ^^
config/boot.rb:1:1: C: Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
^
config/environment.rb:1:1: C: Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
# Load the Rails application.
^
config/environments/development.rb:1:1: C: Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
Rails.application.configure do
^
config/environments/development.rb:2:81: C: Metrics/LineLength: Line is too long. [85/80]
  # Settings specified here will take precedence over those in config/application.rb.
                                                                                ^^^^^
config/environments/development.rb:31:81: C: Metrics/LineLength: Line is too long. [87/80]
  # Store uploaded files on the local file system (see config/storage.yml for options).
                                                                                ^^^^^^^
config/environments/production.rb:1:1: C: Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
Rails.application.configure do
^
config/environments/production.rb:2:81: C: Metrics/LineLength: Line is too long. [85/80]
  # Settings specified here will take precedence over those in config/application.rb.
                                                                                ^^^^^
config/environments/production.rb:17:81: C: Metrics/LineLength: Line is too long. [87/80]
  # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"]
                                                                                ^^^^^^^
config/environments/production.rb:18:81: C: Metrics/LineLength: Line is too long. [97/80]
  # or in config/master.key. This key is used to decrypt credentials (and other encrypted files).
                                                                                ^^^^^^^^^^^^^^^^^
config/environments/production.rb:38:81: C: Metrics/LineLength: Line is too long. [87/80]
  # Store uploaded files on the local file system (see config/storage.yml for options).
                                                                                ^^^^^^^
config/environments/production.rb:44:81: C: Metrics/LineLength: Line is too long. [96/80]
  # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ]
                                                                                ^^^^^^^^^^^^^^^^
config/environments/production.rb:46:81: C: Metrics/LineLength: Line is too long. [96/80]
  # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
                                                                                ^^^^^^^^^^^^^^^^
config/environments/production.rb:54:22: C: Layout/SpaceInsideArrayLiteralBrackets: Do not use space inside array brackets.
  config.log_tags = [ :request_id ]
                     ^
config/environments/production.rb:54:34: C: Layout/SpaceInsideArrayLiteralBrackets: Do not use space inside array brackets.
  config.log_tags = [ :request_id ]
                                 ^
config/environments/production.rb:59:81: C: Metrics/LineLength: Line is too long. [84/80]
  # Use a real queuing backend for Active Job (and separate queues per environment).
                                                                                ^^^^
config/environments/production.rb:66:81: C: Metrics/LineLength: Line is too long. [100/80]
  # Set this to true and configure the email server for immediate delivery to raise delivery errors.
                                                                                ^^^^^^^^^^^^^^^^^^^^
config/environments/production.rb:81:81: C: Metrics/LineLength: Line is too long. [83/80]
  # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name')
                                                                                ^^^
config/environments/production.rb:83:10: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
  if ENV["RAILS_LOG_TO_STDOUT"].present?
         ^^^^^^^^^^^^^^^^^^^^^
config/environments/production.rb:110:81: C: Metrics/LineLength: Line is too long. [97/80]
  # config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver
                                                                                ^^^^^^^^^^^^^^^^^
config/environments/production.rb:111:81: C: Metrics/LineLength: Line is too long. [114/80]
  # config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session
                                                                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
config/environments/test.rb:1:1: C: Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
# The test environment is used exclusively to run your application's
^
config/environments/test.rb:7:81: C: Metrics/LineLength: Line is too long. [85/80]
  # Settings specified here will take precedence over those in config/application.rb.
                                                                                ^^^^^
config/environments/test.rb:8:1: C: Layout/TrailingWhitespace: Trailing whitespace detected.
config/initializers/application_controller_renderer.rb:1:1: C: Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
# Be sure to restart your server when you modify this file.
^
config/initializers/assets.rb:1:1: C: Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
# Be sure to restart your server when you modify this file.
^
config/initializers/backtrace_silencers.rb:1:1: C: Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
# Be sure to restart your server when you modify this file.
^
config/initializers/backtrace_silencers.rb:3:81: C: Metrics/LineLength: Line is too long. [107/80]
# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
                                                                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
config/initializers/backtrace_silencers.rb:6:81: C: Metrics/LineLength: Line is too long. [112/80]
# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
                                                                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
config/initializers/content_security_policy.rb:1:1: C: Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
# Be sure to restart your server when you modify this file.
^
config/initializers/content_security_policy.rb:15:81: C: Metrics/LineLength: Line is too long. [110/80]
#   policy.connect_src :self, :https, "http://localhost:3035", "ws://localhost:3035" if Rails.env.development?
                                                                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
config/initializers/content_security_policy.rb:22:81: C: Metrics/LineLength: Line is too long. [107/80]
# Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) }
                                                                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
config/initializers/cookies_serializer.rb:1:1: C: Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
# Be sure to restart your server when you modify this file.
^
config/initializers/filter_parameter_logging.rb:1:1: C: Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
# Be sure to restart your server when you modify this file.
^
config/initializers/inflections.rb:1:1: C: Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
# Be sure to restart your server when you modify this file.
^
config/initializers/mime_types.rb:1:1: C: Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
# Be sure to restart your server when you modify this file.
^
config/initializers/wrap_parameters.rb:1:1: C: Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
# Be sure to restart your server when you modify this file.
^
config/initializers/wrap_parameters.rb:6:81: C: Metrics/LineLength: Line is too long. [96/80]
# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
                                                                                ^^^^^^^^^^^^^^^^
config/puma.rb:1:1: C: Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
# Puma can serve each request in a thread from an internal thread pool.
^
config/puma.rb:7:31: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
                              ^^^^^^^^^^^^^^^^^^^
config/puma.rb:8:31: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count }
                              ^^^^^^^^^^^^^^^^^^^
config/puma.rb:11:81: C: Metrics/LineLength: Line is too long. [85/80]
# Specifies the `port` that Puma will listen on to receive requests; default is 3000.
                                                                                ^^^^^
config/puma.rb:13:23: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
port        ENV.fetch("PORT") { 3000 }
                      ^^^^^^
config/puma.rb:17:23: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
environment ENV.fetch("RAILS_ENV") { "development" }
                      ^^^^^^^^^^^
config/puma.rb:17:38: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
environment ENV.fetch("RAILS_ENV") { "development" }
                                     ^^^^^^^^^^^^^
config/routes.rb:1:1: C: Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
Rails.application.routes.draw do
^
config/spring.rb:1:1: C: Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
Spring.watch(
^
config/spring.rb:2:3: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
  ".ruby-version",
  ^^^^^^^^^^^^^^^
config/spring.rb:3:3: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
  ".rbenv-vars",
  ^^^^^^^^^^^^^
config/spring.rb:4:3: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
  "tmp/restart.txt",
  ^^^^^^^^^^^^^^^^^
config/spring.rb:5:3: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
  "tmp/caching-dev.txt"
  ^^^^^^^^^^^^^^^^^^^^^
db/seeds.rb:1:1: C: Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
# This file should contain all the record creation needed to seed the database with its default values.
^
db/seeds.rb:1:81: C: Metrics/LineLength: Line is too long. [103/80]
# This file should contain all the record creation needed to seed the database with its default values.
                                                                                ^^^^^^^^^^^^^^^^^^^^^^^
db/seeds.rb:2:81: C: Metrics/LineLength: Line is too long. [111/80]
# The data can then be loaded with the rails db:seed command (or created alongside the database with db:setup).
                                                                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
db/seeds.rb:6:81: C: Metrics/LineLength: Line is too long. [81/80]
#   movies = Movie.create([{ name: 'Star Wars' }, { name: 'Lord of the Rings' }])
                                                                                ^
test/application_system_test_case.rb:1:1: C: Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
require "test_helper"
^
test/application_system_test_case.rb:1:9: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
require "test_helper"
        ^^^^^^^^^^^^^
test/channels/application_cable/connection_test.rb:1:1: C: Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
require "test_helper"
^
test/channels/application_cable/connection_test.rb:1:9: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
require "test_helper"
        ^^^^^^^^^^^^^
test/channels/application_cable/connection_test.rb:3:7: C: Style/ClassAndModuleChildren: Use nested module/class definitions instead of compact style.
class ApplicationCable::ConnectionTest < ActionCable::Connection::TestCase
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
test/test_helper.rb:1:1: C: Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
ENV['RAILS_ENV'] ||= 'test'
^
test/test_helper.rb:5:7: C: Style/ClassAndModuleChildren: Use nested module/class definitions instead of compact style.
class ActiveSupport::TestCase
      ^^^^^^^^^^^^^^^^^^^^^^^
test/test_helper.rb:9:81: C: Metrics/LineLength: Line is too long. [82/80]
  # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
                                                                                ^^

40 files inspected, 170 offenses detected
$

Describe the solution you'd like

I'd like to have some configuration enabled by default not to report offenses for these files.

Describe alternatives you've considered

Execute this command to ignore these offenses by creating .rubocop_todo.yml

$ bundle exec rubocop --auto-gen-config

Usually when I create .rubocop_todo.yml I tend to ignore more and more files to .rubocop_todo.yml rather than addressing offenses. I prefer not to create .rubocop_todo.yml as much as possible.

Additional context

I may misunderstand what RuboCop Rails should address.

Detect `delegate` to self

I discovered some code like this:

delegate :foo, to: self

foo is a class method. So calling foo in an instance method would be equivalent to self.class.foo.

I can't see how this confusing indirection would ever make sense. If a method needs to be available as both an instance and a class method, then there's probably a problem in the design.

Any thoughts? Should rubocop-rails detect this?

ConvertTry produces invalid Ruby

Expected behavior

Given this source:

class Foo
  def foo
    self.try(:bar).try(:baz)
  end
end

And this Rubocop config:

AllCops:
  TargetRubyVersion: 2.3

Rails:
  Enabled: true

Rails/SafeNavigation:
  ConvertTry: true

I expected auto-correction to produce working Ruby.

Actual behavior

Auto-correction produces this output:

# frozen_string_literal: true

class Foo
  def foo
    &.bar&.baz
  end
end

Which does not parse. The Rubocop output is:

Inspecting 1 file
E

Offenses:

test.rb:1:1: C: [Corrected] Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
class Foo
^
test.rb:3:1: E: Lint/Syntax: class definition in method body
(Using Ruby 2.3 parser; configure using TargetRubyVersion parameter, under AllCops)
class Foo
^^^^^
test.rb:3:5: C: [Corrected] Rails/SafeNavigation: Use safe navigation (&.) instead of try.
    self.try(:bar).try(:baz)
    ^^^^^^^^^^^^^^^^^^^^^^^^
test.rb:3:5: C: [Corrected] Style/RedundantSelf: Redundant self detected.
    self.try(:bar).try(:baz)
    ^^^^^^^^^^^^^^
test.rb:5:10: E: Lint/Syntax: unexpected token tANDDOT
(Using Ruby 2.3 parser; configure using TargetRubyVersion parameter, under AllCops)
    &.bar&.baz
         ^^

1 file inspected, 5 offenses detected, 3 offenses corrected

Steps to reproduce the problem

Run rubocop -a with the above source and config. Note that setting the target Ruby version to 2.2 (the lowest supported) produces working Ruby (it leaves the try in place).

RuboCop version

0.68.0 (using Parser 2.6.0.0, running on ruby 2.3.3 x86_64-darwin17)

Rails/TimeZone autofix broken for "DateTime.now"

So I had somewhere in the code DateTime.now. When running the linter (rubocop command) I was getting this error:

Rails/TimeZone: Do not use DateTime.now without zone. Use one of Time.zone.now, DateTime.current, DateTime.now.in_time_zone, DateTime.now.utc, DateTime.now.getlocal, DateTime.now.xmlschema, DateTime.now.iso8601, DateTime.now.jisx0301, DateTime.now.rfc3339, DateTime.now.httpdate, DateTime.now.to_i, DateTime.now.to_f instead.

which is correct.

But, when I run rubocop --safe-auto-correct that string get changed to DateTime.zone.now which is incorrect – DateTime does not implement zone method:

$ DateTime.zone
NoMethodError: undefined method `zone' for DateTime:Class

Expected behavior

After running autofix, I expect DateTime.now changes to Time.zone.now or something similar.

RuboCop version

$ bundle exec rubocop -V                                                                              
0.72.0 (using Parser 2.6.3.0, running on ruby 2.4.1 x86_64-darwin18)

Rails/ReflectionClassName gives false positive

Expected behavior

It should not mark an error when a string is given

Actual behavior

Describe here what actually happened.

Steps to reproduce the problem

app/models/spotlight/page.rb:13:33: C: Rails/ReflectionClassName: Use a string has value for a class_name.
    belongs_to :last_edited_by, class_name: Spotlight::Engine.config.user_class, optional: true

However Spotlight::Engine.config.user_class is returning a string.

RuboCop version

$ bundle exec rubocop -v
0.64.0

Cop suggestion: Rails/InvalidActionFilterOption

Action filter ignores :if option when :if and :only are used together. See rails/rails#9703

skip_before_filter :login_required, only: :show, if: :trusted_origin? # the :if option will be ignored.

I think it is useful to be able to detect the above problems with RuboCop. The output example is following:

Inspecting 1 file
C

Offenses:

app/controllers/login_controller.rb:2:3: C: Rails/InvalidActionFilterOption: `:if` option will be ignored when `:if` and `:only` option are used together.
skip_before_filter :login_required, only: :show, if: :trusted_origin? # the :if option will be ignored.
                                                 ^^^^^^^^^^^^^^^^^^^^

1 file inspected, 1 offenses detected

Rails/SkipsModelValidations is inconsistence with touch

Rails/SkipsModelValidations cop doesn't complain about the following relation:

belongs_to :user, touch: true

but it does complain in its test (Avoid using touch because it skips validations.):

it { should belong_to(:user).touch(true) }

Expected behavior

Complain in both cases or in any of them. I would say that it should also complain in the relation.

RuboCop version

0.47.1

Originally opened at rubocop/rubocop#4098

Rails/FilePath - False positive on blob with slash

Code that returns a listing of sub directories, without files, within a Rails root raises an offense:

Rails/FilePath: Please use Rails.root.join('path', 'to') instead.

Expected behavior

When running $ rubocop on any ruby file within a Rails project:

Dir[Rails.root.join('app', 'services', '{*/}')]

Should not raise the "Rails/FilePath" offense for the blob slash that returns a sub directory listing.

Actual behavior

Dir[Rails.root.join('app', 'services', '{*/}')]

Raises the "Rails/FilePath" offense due to the slash.

Steps to reproduce the problem

When running the $ rubocop, a "Rails/FilePath" offense is raised on any ruby file within a Rails project that has the following code: Rails.root.join('<dir>', '<dir>', '{*/}').

RuboCop version

0.67.2 (using Parser 2.6.2.1, running on ruby 2.5.3 x86_64-darwin18)

Time.current is getting autocorrected to Time.zone.current

Expected behavior

I believe Time.current should get updated to Time.zone.now.

Actual behavior

I believe Time.current gets updated to Time.zone.current, which doesn't exist.

Steps to reproduce the problem

  • Create a Rails repo
  • Add Rubocop
  • Set Rails/TimeZone to EnforcedStyle: strict.
  • Add Time.current

Is this potentially related to #6346?

RuboCop version

0.66.0 (using Parser 2.6.0.0, running on ruby 2.5.3 x86_64-linux)

New COP to Restrict Business Logic to certain parts of a Rails application

One opinionated approach to breaking apart Rails applications is to move business logic to isolated business objects, keeping it out of Controllers, ActiveRecord Models, Helpers, Views, etc. It also goes hand-in-hand with the pattern of Skinny Controllers, Skinny Models. This can allow for more Object Oriented code, PORO's, and faster/easier unit testing.

Working with a team of 60 Ruby engineers and establishing some of these rules has drastically improved our code organization, unit testing, and ease of code changing.

With this opinionated approach, a cop which ensures keeping business logic out of parts of the rails application that we want to remain skinny and push it to business objects, value objects, view objects, service objects, query objects, form objects, policy objects and decorator objects.

Items considered business logic would be things like if, else, while, until, case, rescue, &&, || or regexp. Common items which make business decisions in our code and ones you would want to test.

The cop would check for the above syntax in certain files and raise an error if it's in a file/class where it is not allowed.

Note: Much of this comes from lengthy discussion with Sandi Metz, TJ Stankus and Jim Gay over the years around OO and Rails.

Configuration of cop would be disabled by default (since it's an opinionated approach) and include parameter for an array of files patterns which would be included. By default, the config would look be:

Rails/BusinessLogicNotAllowed:
  Description: 'Prevent the use of business logic in parts of the rails application.'
  Enabled: false
  Include:
    - app/controllers/**/*.rb
    - app/models/**/*.rb
    - app/views/**/*.erb

See also:

New cop: use bang modifiers for ActiveRecord methods in transactions

Transactions in Rails:

Transactions reset the state of records through a process called a rollback. In Rails, rollbacks are only triggered by an exception. This is a crucial point to understand; I saw several transaction blocks that would never rollback because the containing code could not throw an exception.

  # bad
  ::ActiveRecord::Base.transaction do
    @record = ::Record.find_by(id: 1)
    @record.update(attr: attr)
    @record.save
    @record.destroy
  end

  # good
  ::ActiveRecord::Base.transaction do
    @record = ::Record.find(1) # or ::Record.find_by!(id: 1)
    @record.update!(attr: attr)
    @record.save!
    @record.destroy!
  end

I can put a PR together if I get the go-ahead.

Installation instruction?

I feel stupid, but does this gem missing simple installation guide? i got used to them in other rubocop gems.

Rails/TimeZone: `DateTime.new` is wrongly corrected to `DateTime.zone.new`

When EnforcedStyle is flexible(default), Rails/TimeZone cop will correct DateTime.new to DateTime.zone.new. It breaks codes because DateTime.zone is not defined by Rails.

See: https://api.rubyonrails.org/classes/DateTime.html

Expected behavior

  • DateTime.new is left as it is.
  • DateTime.new is corrected to Time.zone.new as EnforcedTyope: strict

Actual behavior

  • DateTime.new is corrected to DateTime.zone.new

Other DateTime's methods (now, local, parse, at, current) are also corrected to DateTime.zone.*.

Steps to reproduce the problem

$ gem install rubocop -v 0.71.0
$ gem install rubocop-rails -v 2.0
$ echo 'require: rubocop-rails' > .rubocop.yml

$ echo 'DateTime.new' > a.rb

$ rubocop --only Rails/TimeZone --auto-correct a.rb
Inspecting 1 file
C

Offenses:

a.rb:1:10: C: [Corrected] Rails/TimeZone: Do not use DateTime.new without zone. Use one of Time.zone.now, DateTime.current, DateTime.new.in_time_zone, DateTime.new.utc, DateTime.new.getlocal, DateTime.new.xmlschema, DateTime.new.iso8601, DateTime.new.jisx0301, DateTime.new.rfc3339, DateTime.new.httpdate, DateTime.new.to_i, DateTime.new.to_f instead. (https://github.com/rubocop-hq/rails-style-guide#time, http://danilenko.org/2012/7/6/rails_timezones)
DateTime.new
         ^^^

1 file inspected, 1 offense detected, 1 offense corrected

$ cat a.rb
DateTime.zone.new

RuboCop version

$ rubocop -V
0.71.0 (using Parser 2.6.3.0, running on ruby 2.6.2 x86_64-darwin17)

Rails/Output behavior changes depending on relative or absolute config path

I've created a repo that can reproduce this issue: https://github.com/ndbroadbent/rubocop-bug

From the README:


Run ./script.sh.

With file

git clone https://github.com/ndbroadbent/rubocop-bug.git /tmp/rubocop-bug
cd /tmp/rubocop-bug

rubocop
Inspecting 1 file
.

1 file inspected, no offenses detected
rubocop -c .rubocop.yml
Inspecting 1 file
.

1 file inspected, no offenses detected
rubocop -c /tmp/rubocop-bug/.rubocop.yml
Inspecting 1 file
W

Offenses:

app/models/test_model.rb:6:5: W: Lint/UnneededCopDisableDirective: Unnecessary disabling of Rails/Output.
    # rubocop:disable Rails/Output
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

1 file inspected, 1 offense detected

With stdin

cat app/models/test_model.rb | rubocop -c /tmp/rubocop-bug/.rubocop.yml \
    -s /tmp/rubocop-bug/app/models/test_model.rb
Inspecting 1 file
.

1 file inspected, no offenses detected
cp app/models/test_model.rb /tmp/test_model.rb
cat app/models/test_model.rb | rubocop -c /tmp/rubocop-bug/.rubocop.yml \
    -s /tmp/test_model.rb
Inspecting 1 file
W

Offenses:

/tmp/test_model.rb:6:5: W: Lint/UnneededCopDisableDirective: Unnecessary disabling of Rails/Output.
    # rubocop:disable Rails/Output
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

1 file inspected, 1 offense detected

Rails/CreateTableWithTimestamps shouldn't warn when id: false is used

In migrations you can create a join table like so:

create_table :games, :genres, id: false do |t|
  t.integer :game_id
  t.integer :genre_id
end

But Rails/CreateTableWithTimestamps will warn about this code because the table is being created without timestamps. Join tables shouldn't have timestamps, so this is a false positive.

https://guides.rubyonrails.org/association_basics.html#creating-join-tables-for-has-and-belongs-to-many-associations

Replace find_by_id with find

Is your feature request related to a problem? Please describe.

Currently rubocop-rails replaces find_by_id with find_by id: and that looks terrible

Describe the solution you'd like

Replace find_by_id with find

New cop suggestion: check if a defined route has a corresponding controller action

My suggestion is to have a cop, which checks, that all defined routes in config/routes.rb have corresponding controller actions. For example, if we define:

resources :countries

the following routes are generated:

                countries GET    /countries(.:format)                                                                     countries#index
                          POST   /countries(.:format)                                                                     countries#create
              new_country GET    /countries/new(.:format)                                                                 countries#new
             edit_country GET    /countries/:id/edit(.:format)                                                            countries#edit
                  country GET    /countries/:id(.:format)                                                                 countries#show
                          PATCH  /countries/:id(.:format)                                                                 countries#update
                          PUT    /countries/:id(.:format)                                                                 countries#update
                          DELETE /countries/:id(.:format)                                                                 countries#destroy

However, if the controller has only implemented the #index action:

class CountriesController < ApplicationController
  def index
    render json: Country.all
  end
end

the cop should raise an error/warning.

Handle `RescuedExceptionsVariableName` with `rescue_from`

Following what have been done in the Naming/RescuedExceptionsVariableName cop in the rubocop repo, we should also handle the Rails version that use rescue_from:

class MyController < ApplicationController
  rescue_from MyException do |exception| # <= should be flagged with an offense
    # do something
  end
end

Should this cop read the configuration of Naming/RescuedExceptionsVariableName or have its own duplicated ?

RuboCop::Cop::Rails not defined (NameError)

When rubocop-rails is loaded before Rails is loaded in conjunction with the latest rubocop 0.72, the following error occurs:

rubocop-rails-2.0.1/lib/rubocop/cop/rails_cops.rb:9:in 'remove_const': constant RuboCop::Cop::Rails not defined (NameError)

RuboCop version

0.72.0 (using Parser 2.6.3.0, running on ruby 2.5.3 x86_64-darwin18)


I'm working on a PR to fix this now...

Initial Release

I'm adding this ticket, as a place to track down what needs to be done for an initial release.

@koic just cut the very first release of rubocop-performance and I guess he'll now replicate the process here.

@koic, what remains to be done?

Rails/FilePath suggests broken behavior

In Rails 5.1, File.join(Rails.root, 'public', file_url) returns the correct value: => "/Users/waldavis/Documents/sandbox/emc/public/uploads/52c9853abb1e47e651c231ee8f0c5e9e.rtf"

Rubocop-rails raises this correction: Rails/FilePath: Please use Rails.root.join('path', 'to') instead.

Rails.root.join('public', file_url) returns => #<Pathname:/uploads/52c9853abb1e47e651c231ee8f0c5e9e.rtf>.

file_url.class => String.

I have worked around this by setting a variable to the value of Rails.root, and then Rubocop doesn't care about my use of File.join.

New Cop: Explicit enum definition

Is your feature request related to a problem? Please describe.

Enum has two definition styles.

class Item
  enum category: %i[bar baz]
  enum category: {
    bar: 0,
    baz: 1,
  }
end

They have the same meaning. But I like the latter style.
If I add foo categorybeforebar, the enum breaks! Because the order will be changed by adding foo`.

class Item
  enum category: %i[foo bar baz]
end

We can avoid the bug by using the explicit style.

Describe the solution you'd like

Add a cop to detect enum with an array.

Describe alternatives you've considered

Probably we can make the cop configurable to enforce the opposite style.
Personally I think we do not need configurable cop at least the first implementation.

I do not oppose implementing the configuration, but we should mention the risk of the implicit style in the documentation.

Additional context

none

gem post-install instructions are pretty confusing.

I've added gem "rubocop-rails" to my Gemfile and got following output on bundle install:

Post-install message from rubocop-rails:
rubocop-rails is renamed to rubocop-rails_config. To migrate to new gem, install rubocop-rails_config instead of rubocop-rails.

gem "rubocop-rails_config"

Then, run update command.

$ bundle exec rails generate rubocop_rails_config:update

Latest version of rubocop-rails on rubygems is 1.5.0 while in this repo seems to be 0.5.0 as far as I understand:

https://github.com/rubocop-hq/rubocop-rails/blob/86a09ab0d94fa3cc24430af6689b7908e23c177c/lib/rubocop/rails/version.rb

Should one install this gem from git rather than from rubygems? Or should we use rails_config?

change_column_null should not be included in BulkChangeTable cop

As it stands now, the BulkChangeTable cop flags uses of change_column_null. However, there is no corresponding method on ActiveRecord::ConnectionAdapters::Table to replace it with as there is with change_column_default and Table#change_default. The closest thing is Table#change, but that requires the developer to repeat the entire column definition (which is why change_column_null exists in the first place in addition to change_column).

Am I missing a reasonable replacement for change_column_null?

Prefer using slashes in Rails/FilePath cop

Under Windows, Rails.root.join('app', 'models', 'goober') is equal to Rails.root.join('app/models/goober'). They both return a string with forward slashes.

I'm in favor of always using the simple slashes and deprecating the previous join. The current cop suggests this is

to avoid bugs on operating system that don't use '/' as the path separator

but there is no evidence of such bugs.

More discussion of the issue here: https://twitter.com/tenderlove/status/842064491936280576

c6-l0cfwyaa6rvc


Expected behavior

Rails/FilePath should treat as:

# bad
Rails.root.join('app', 'models', 'goober')

# good
Rails.root.join('app/models/goober')

Actual behavior

Today it treats the following as:

# good
Rails.root.join('app', 'models', 'goober')

# bad
Rails.root.join('app/models/goober')

Incorrect auto-correction: Time.new -> Time.zone.new

Rails/TimeZone will substitute Time.new to Time.zone.new with --auto-correct option.

However, Time.zone.new is not a constructor of TimeWithZone.
It should be Time.zone.local.


Expected behavior

Substitutes Time.new with Time.zone.local.

Actual behavior

Substitutes Time.new with Time.zone.new.

Steps to reproduce the problem

$ gem install rubocop -v 0.72.0
$ gem install rubocop-rails -v 2.2.0
$ echo 'require: rubocop-rails' > .rubocop.yml
$ echo 'Time.new(2016, 7, 8, 12, 34, 56)' > a.rb
$ rubocop --only Rails/TimeZone --auto-correct a.rb
Inspecting 1 file
C

Offenses:

a.rb:1:6: C: [Corrected] Rails/TimeZone: Do not use Time.new without zone. Use one of Time.zone.local, Time.current, Time.new.in_time_zone, Time.new.utc, Time.new.getlocal, Time.new.xmlschema, Time.new.iso8601, Time.new.jisx0301, Time.new.rfc3339, Time.new.httpdate, Time.new.to_i, Time.new.to_f instead. (https://github.com/rubocop-hq/rails-style-guide#time, http://danilenko.org/2012/7/6/rails_timezones)
Time.new(2016, 7, 8, 12, 34, 56)
     ^^^

1 file inspected, 1 offense detected, 1 offense corrected
$ cat a.rb
Time.zone.new(2016, 7, 8, 12, 34, 56)

RuboCop version

$ rubocop -V
0.72.0 (using Parser 2.6.3.0, running on ruby 2.6.2 x86_64-darwin17)

Cop suggestion: Referencing constants from within a view

I often see code in a view which directly accesses a model, e.g.

<% if ShippingPrice.new(@order).free? %>
  This order qualifies for free shipping
<% end %>

This implies a tight coupling between different layers of the application. Also, it seems wrong for the view to access the model layer directly, rather than having data passed via the controller.

This would be slightly better:

<% if @shipping_price.free? %>

But I would typically aim to have the implementation behind a simpler interface, and avoid adding extra instance variables, e.g.

<% if @order.free_shipping? %>

(@order could be an ActiveRecord model which delegates to ShippingPrice, or it could be a decorator or presenter).

Any thoughts?

Style/MixinUsage in default rails app

Moved from rubocop/rubocop#5237

Every fresh rails app has bin/{setup,update} with toplevel include FileUtils.

This cop does not provide autofix, and to fix this warning it requires remastering this files, which results in conflicts when updating rails.

Should this files be added to default exclude list for this cop?

Rack dependency issue

Is your feature request related to a problem? Please describe.

Hey!
I wanted to upgrade my app to include rubocop-rails gem.
I encountered with the problem that the rack gem has became a runtime dependancy instead of a development one.
In this case for us, it basically means a rails 5 dependancy, so basically we are not able to upgrade.

Describe the solution you'd like

Is there a way to be backward compatible with rack? Or will rubocop have an option to include the rails cop further?

Rails Cop Idea: `Rails.root.join`

Would love a cop that specifies to always use syntax:

Rails.root.join('app', 'models', 'goober') # good

over:

# bad
Rails.root.join('app/models/goober')
"#{Rails.root}/app/models/goober"
File.join(Rails.root, 'app/models/goober')
# etc...

We've got a bunch of formats littered throughout our codebase.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.