Skip to content

Instantly share code, notes, and snippets.

@pocke
Created June 24, 2020 08:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pocke/1962a9212e879c451936b81d241880fe to your computer and use it in GitHub Desktop.
Save pocke/1962a9212e879c451936b81d241880fe to your computer and use it in GitHub Desktop.
rules:
- id: sample.delete_all
pattern:
- delete_all
- update_all
message: |
これらはvalidationやcallbackをスキップするので危険かもしれません。
justification:
- どうしても高速に update/destroy したい場合
- callbacks/validations が不要な場合
before:
- records.delete_all
- records.update_all
after:
- records.each(&:destroy)
- |
records.each do |record|
record.update(field: nil)
end
- id: sample.save_not_conditional
pattern:
- "save(!validate: false, ...) [!conditional]"
- "update(...) [!conditional]"
- "update_attributes(...) [!conditional]"
- "destroy(...) [!conditional]"
message: |
save / update(_attributes) / destroy は失敗するとfalseを返します。
戻り値をチェックするか、 `!` 付きのメソッドを呼んでください。
justification:
- "StripeのメソッドはActiveRecord由来ではないので `!` 付きでなくても問題ありません。"
before:
- record.save()
- "record.update(foo: bar)"
- "record.update(attrs)"
after:
- if record.save() then do_something end
- "record.save(validate: false)"
- "record.update(foo: 1) or fail"
- id: sample.skip_validation
pattern:
- "save(validate: false)"
- "save!(validate: false)"
message: "validationをスキップするのは危険です。"
justification:
- When you want to skip validation
- When you have done validation code in other than ActiveRecord's validation mechanism
- id: sample.net_http
pattern: Net::HTTP
message: Use Faraday to make Web api calls
before:
- Net::HTTP.get(url)
after:
- Faraday.new.get_content(url)
- id: sample.oj
pattern:
- JSON.parse
- JSON.generate
message: Use Oj for JSON load and dump
- id: sample.metaprogramming_abuse
pattern:
- classify
- constantize
- eval
- instance_values
- safe_constantize
message: "本当にメタプログラミングが必要か3回考えてください。"
- id: sample.activesupport.try
pattern: "try"
message: "tryではなく &. 演算子を使ってください"
- id: kibela.activerecord.serialize
pattern: "serialize(:symbol:, ...)"
message: "ActiveRecordのserializeを使う必要はありません。jsonb型をそのまま使ってください。"
- id: kibela.user_roles
pattern: "User.roles[:symbol:]"
message: "User.roles[:member] は多くの場合で必要ありません。たとえばupdateやwhereではenum symbolを使えます。"
- id: kibela.current_user_locale
pattern: "current_user.locale"
message: "current_userはログインしていない場合nilになります。 I18n.localeを使ってください。"
- id: kibela.order_by_created_at
pattern: "order(created_at: :symbol:, !id: :symbol:)"
message: "order(created_at: ...) は order(id: ...) または order(created_at: ..., id: ...) と書くべきです。idは常にindexが有効だし、1ms未満の時間差で作成されたとしても必ず順番が確定するからです。"
- id: kibela.order_by_string
pattern:
- "order(:dstr:)"
- "where(:dstr:)"
- "find(:dstr:)"
- "exists?(:dstr:)"
message: "文字列によるSQL構築は本当に必要ですか? SQL Injection を引き起こさないように気をつけてください。"
- id: kibela.block_call
pattern:
- "yield"
message: "yieldではなくblock.callを使いましょう。そのほうが渡す引数が明確になります。"
- id: kibela.graphql_null_after_type
pattern: "field(:symbol:, _, !null: _, ...)"
message: "GraphQLのfield宣言は、typeの直後にnullオプションを書いてください。GraphQL schemaでは `T` (nullable) と `T!` (non-null) と書くように、nullabilityは型の一部なのです。"
- id: kibela.yard_class_name
pattern: "class_name()"
message: "Class#class_name は yard gem による拡張なのでproductionでは使えません。必要なのはビルトインメソッドの Class#name ではないですか。"
- id: kibela.cgi_escape
pattern: "CGI.escape"
message: "path component のescapeに CGI.escape を使うのは不適切です。 URI::DEFAULT_PARSER.escape を使ってください"
- id: kibela.connection_type_without_resolver
pattern: "field(:symbol:, _.connection_type, ..., !resolve: _, ...)"
message: "Relay connection に resolver が設定されていません。 AR::Relation に対するconnectionは resolver でソートを指定すべきです。"
- id: kibela.accessible_for
pattern: "accessible_for(_)"
message: "accessible_for(user) は古いメソッドです。 readable_by(user) または manageable_by(user) を使ってください"
justification: "testでは一部残っています。余裕があれば新しいメソッドに書き換えてください"
- id: kibela.accessible_for_p
pattern: "accessible_for?(_)"
message: "accessible_for?(user) は古いメソッドです。 readable_by?(user) または manageable_by?(user) を使ってください"
justification: "testでは一部残っています。余裕があれば新しいメソッドに書き換えてください"
- id: kibela.prefer_fetch_for_rails_secrets
pattern:
subject: "Rails.application.'credentials.'key()"
where:
key: '/.+/'
credentials: '/(?:secrets|credentials)/'
message: "`Rails.application.secrets.fetch(...)` を使いましょう。"
before:
- "Rails.application.secrets.foo"
- "Rails.application.credentials.foo"
after:
- "Rails.application.secrets.fetch(:foo)"
- "Rails.application.credentials.fetch(:foo)"
- id: kibela.prefer_fetch_for_graphql_context
pattern: "context.[](:symbol:)"
message: "GraphQL contextのエントリの参照は `context.fetch(...)` を使いましょう。"
before:
- "context[:foo]"
after:
- "context.fetch(:foo)"
- id: kibela.migration_belongs_to
message: "外部キーを定義する際は`integer`ではなく`belongs_to`や`references`を使いましょう。これによりデータ型がbigintになります。"
before:
- 't.integer :user_id'
- 't.integer :user_id, index: true, null: false'
- 'add_column :notes, :user_id, :integer, null: false, index: true'
after:
- 't.belongs_to :user'
- 't.references :user_id, index: true, null: false'
- 'add_reference :notes, :user, :integer, null: false, index: true'
pattern:
- subject: "t.integer(:symbol: as 'column, ...)"
where:
column: '/.+_id/'
- subject: "add_column(_, :symbol: as 'column, :integer, ...)"
where:
column: '/.+_id/'
preprocessor:
.haml: hamlit compile -
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment