Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Model error as object #32313

Merged
merged 22 commits into from Apr 24, 2019
Merged

Model error as object #32313

merged 22 commits into from Apr 24, 2019

Conversation

@lulalala
Copy link
Contributor

@lulalala lulalala commented Mar 21, 2018

Summary

Add ActiveModel::Error class for encapsulating a single error. It handles message generation and details access.
Utilize this in Errors class, changing it from a hash based interface, to an array of Error objects. Add more flexible query methods like where.

Introduction

ActiveModel#errors interface is currently not very object oriented. For some complex use cases, this design made it a bit tedious to use. I feel these issues can be remedied by encapsulating each individual error as an object.

Last year I implemented AdequateErrors gem to do this, and it solved many of my problems. I later found out that back in 2016, @eprothro suggested the same idea too on the core mailinglist, and Rafael was positive about this. So I made this PR.

I've made it to respect Rails’ deprecation policy. As this contains breaking changes, can this go straight into Rails 6.0?

I will fix other specs/add doc/performance tuning once interface is finalized.

Benefits

More flexible query interface such as where

It’s easy to query one particular object using the where clause.

model.errors.where(:name, :foo, bar: 3).first

delete, add, added?, where all share the same method signature (attribute, type, options). So we are able to delete specific errors now:

model.errors.delete(:name, :too_powerful, level: 9000)

Testing is more precise and flexible

We can now test if “foo” error exists, regardless of its options hash.

model.errors.add(:name, :too_powerful, level: 9000)

model.errors.added?(:name, :too_powerful, level: 9000) # returns true
model.errors.added?(:name, :too_powerful) # will be false in the past, but be true now.

In the past, added? works by re-render the message and compare it against current message. Therefore if level is not provided, it will return false. In the PR, added? only compare Error's attributes against what's provided, so it can be more general or more specific depending on the needs.

Get message of corresponding details of one particular error

If you saw that name attribute has two foo_error and one bar_error, e.g.:

# model.errors.details
{:name=>[{error: :foo_error, count: 1}, {error: :bar_error}, {error: :foo_error, count: 3}]}

How do you back track the message on the third particular error? With the current implementation, we have to resort to using array indexes:

model.errors.messages[:name][2]

Or we can call generate_message to recreate a message from the details, but that's also tedious.

With OO, we won't have this problem. Error is represented as an object, message and details are its attributes, so accessing those are straightforward:

e = model.errors.where(:name, :foo_error).last
e.full_message
e.options # similar to details, where meta informations such as `:count` is stored.

Lazily evaluating message for internationalization

@morgoth mentioned this issue that when you're adding error, it's translated right away.

# actual:
I18n.with_locale(:pl) { user.error.full_messages } # => outputs EN errors always

# expecting:
I18n.with_locale(:pl) { user.error.full_messages } # => outputs PL errors
I18n.with_locale(:pt) { user.error.full_messages } # => outputs PT errors

This PR addresses this by lazily evaluating messages only when message is called.

Opens possibility to advanced modding

Once errors are objects, it’s easy to add functionality on top of them. We can have custom methods to disable global attribute prefix on error’s full messages.

List of API changes

[]
unchanged, deprecated (use messages_for instead)

as_json, blank?, clear, count, empty?
unchanged

add
unchanged

added?
mostly unchanged, for the one change see "Testing is more precise and flexible"

delete
extended, so we can give more specific condition such as error type or options.

each
If we use each{|attr,msgs|} then it behaves the same as before. Deprecated
If we use each{|error|} then it loops through Error array.

full_message
deprecated as it is no longer needed.
unchanged message is generated in Error.

full_messages, full_messages_for
unchanged

messages_for
new, to replace deprecated []

where
new, query for error objects
generate_message
deprecated Part of Error as message is generated there.

has_key? key?, keys
deprecated

include?, size, to_hash, to_xml, to_a
unchanged

values
deprecated

import
new, imports one error as a nested error. Useful in Form Object and nested attribute error importing.

messages, details
unchanged

Some questions I have

I am not sure what's the policy for marshal across versions. marshal_dump and marshal_load are implemented, but do they have to support marshaling across Rails versions?

This has been done.

Can we deprecate to_xml? I bet is rarely used, and can exists as a gem.

@pixeltrix
Copy link
Member

@pixeltrix pixeltrix commented Mar 21, 2018

@lulalala is there a reason why you can't emulate the hash-based API?

@lulalala
Copy link
Contributor Author

@lulalala lulalala commented Mar 21, 2018

@pixeltrix for the hash like APIs, my thoughts are:

  1. For enumerable methods such as each, I choose to forward them to the error array. Keeping it to enumerate as hash seems to defeat the purpose.
  2. For [] and to_hash, they are emulated.
  3. For values, I removed it. I feel it was there just so errors feels like a hash. It is not useful because having an array of partial error message without knowing each message's respective attribute is useless.

@rafaelfranca
Copy link
Member

@rafaelfranca rafaelfranca commented Mar 21, 2018

Everything that was removed needs to be deprecated first. We don't make breaking changes without deprecation, even in major versions.

marshal_dump and marshal_load are implemented, but do they have to support marshaling across Rails versions?

Yes, we try very hard to make possible that an old Rails version can read data from the new version and also the opposite. This make possible for applications to slowly rollout new versions to production.

activemodel/lib/active_model/error.rb Outdated

module ActiveModel
# Represents one single error
# @!attribute [r] base

This comment has been minimized.

@rafaelfranca

rafaelfranca Mar 21, 2018
Member

We don't use yarn, we use rdoc, so we need to follow the Rails documentation guideline.

@lulalala
Copy link
Contributor Author

@lulalala lulalala commented Mar 22, 2018

Everything that was removed needs to be deprecated first. We don't make breaking changes without deprecation, even in major versions.

Cool. I'll add those back then. How about semantic change such as each?

Yes, we try very hard to make possible that an old Rails version can read data from the new version and also the opposite. This make possible for applications to slowly rollout new versions to production.

Got it, but I still have a question. When marshal_load was added (SHA b3dfd7d), I don't see it tried to accommodate Rails 3 or 4, or am I wrong?

@rafaelfranca
Copy link
Member

@rafaelfranca rafaelfranca commented Mar 22, 2018

Got it, but I still have a question. When marshal_load was added (SHA b3dfd7d), I don't see it tried to accommodate Rails 3 or 4, or am I wrong?

Usually we only think about backward compatibility between two close release. In that case 5.1 and 5.2. Right now it would be 6.0 and 5.2

@rafaelfranca
Copy link
Member

@rafaelfranca rafaelfranca commented Mar 22, 2018

How about semantic change such as each?

Can we introduce a new method with the new semantic and keep the old method with the previous semantic but with deprecation?

@lulalala
Copy link
Contributor Author

@lulalala lulalala commented Mar 22, 2018

Can we introduce a new method with the new semantic and keep the old method with the previous semantic but with deprecation?

I realized there is a better solution. I check arity of the block passed to each. If arity is 1, behave the new way. We can put deprecation notice when the old way is triggered. Thoughts?
https://github.com/rails/rails/pull/32313/files#diff-fdcf8b65b5fb954372c6fe1ddf284c78R196

@rafaelfranca
Copy link
Member

@rafaelfranca rafaelfranca commented Mar 22, 2018

That is a good way. 👍

@lulalala lulalala force-pushed the lulalala:model_error_as_object branch Mar 26, 2018
@lulalala
Copy link
Contributor Author

@lulalala lulalala commented Mar 26, 2018

I have added back existing methods, some with deprecation warning (free to discuss about which to deprecate). The each now should be compatible with old hash block.

The YAML and marshal dumps are also made compatible with past versions. I added tests for each.

I am starting to look into other tests which broke, and I learned a lot about what interface are needed. For example I added group_by_attribute because it is suitable for many occasions.

I'll update in the future once all tests are fixed. After that I'll add doc and optimize :)

@lulalala lulalala force-pushed the lulalala:model_error_as_object branch 2 times, most recently Apr 3, 2018
@lulalala
Copy link
Contributor Author

@lulalala lulalala commented Apr 3, 2018

I think I have fixed almost all tests (the remaining few seems to be sporadic).

I discovered there are many cases of errors[:foo] << 'bar'. We may be able to put a deprecation warning on that, but would involves having a custom array class which overrides << just for that purpose. I hope that's not needed.

Another behavior change is that details will not auto populate with empty array if it is access with a missing key.

If the deprecation proposal here is finalized, I'll start adding code so tests won't have deprecation warning all over the place.

@lulalala lulalala force-pushed the lulalala:model_error_as_object branch to 504b22b May 3, 2018
@lulalala lulalala force-pushed the lulalala:model_error_as_object branch May 9, 2018
@lulalala lulalala force-pushed the lulalala:model_error_as_object branch Jun 28, 2018
@lulalala
Copy link
Contributor Author

@lulalala lulalala commented Jun 30, 2018

Hi @tenderlove, we have met in Ruby Kaigi, and you mentioned that for emulated message arrays, I should freeze those so attempts to append to them would fail. This is now added. Cheers! (Sorry I forgot who was sitting next to you who said I can also ping him as well)

@lulalala lulalala force-pushed the lulalala:model_error_as_object branch 2 times, most recently Sep 24, 2018
@lulalala
Copy link
Contributor Author

@lulalala lulalala commented Sep 29, 2018

Hi @Larochelle, I see that you made a few changes lately to errors.rb. I am slowly trying to add the change you made to here, but after some digging, I am feeling that maybe we can DRY the logic a bit, as generate_message (here as Error#message and full_message) shares a lot of logic. Would you be interested in working with me on this together? Thanks!

@lulalala lulalala force-pushed the lulalala:model_error_as_object branch Sep 29, 2018
@lulalala lulalala force-pushed the lulalala:model_error_as_object branch Sep 29, 2018
@lulalala
Copy link
Contributor Author

@lulalala lulalala commented Jan 22, 2021

@alaarab unfortunately the current design will only lazily evaluate the error messages. Would it help if you generate a copy of the full messages (calling full_mesages should generate a fresh hash each time it is called) right after validation, then manipulate afterwards?

@alaarab
Copy link

@alaarab alaarab commented Jan 22, 2021

@lulalala It feels like that's the route I must go, and to store those errors in an attr_accessor variable on the model so it can be accessed to display errors from on my forms. It just feels 'wrong' to be displaying messages from a custom attribute instead of using object.errors.

I assume this is the least amount of code required to accomplish something like this:

attr_accessor :last_full_error_messages
after_validation :populate_last_error_messages

def populate_last_full_error_messages
  self.last_full_error_messages = self.errors.full_messages
end

If I didn't want a callback, I could also just do this in the controller before the manipulation. I do wish this was just a native behavior though. If a helper existed that replicate the old functionality, (something like errors.full_messages_last_validation which returned an array of error strings after last validation) this would be most preferred. However, if this is not the design direction of Rails, I understand. It just adds to the clunk when doing anything more complicated than Rails boilerplate, since I have to make changes to the views (or possibly the controller) as well.

@thefaded
Copy link

@thefaded thefaded commented Feb 1, 2021

@lulalala, hey, can you please help with nested attributes? Because I can't really reproduce this in Rails 6.1
Consider I have FormObject (< 6.1):

class FormObject
  include ActiveModel::Model
  
  attr_accessor :products
  
  validates :all_products_are_valid
  
  def products_attributes=(params)
     @products = []
     
     products_attributes.each { |p| @products.push(AnotherFormObject.new(p) }
  end
  
  private
  
  def all_products_are_valid
    products.each.with_index do |product, index|
      next if product.valid?

      # Add row_id, to identify row correctly
      product.errors.messages[:row_id] = index

      errors[:products] << product.errors.messages
    end
  end
end

These will produce error object like this:

  {
    products: [
      { supplier_ref: "can't be blank", row_id: 0 },
      { quantity: "must be greater than 0", row_id: 1 }
    ]
  }

But with new approach I can't achieve this at all, I tried these things:

  1. If the just upgrade to 6.1 without changing code above:
{ "products":["is invalid"] }
  1. If use import, as this:
  def all_products_are_valid
    products.each.with_index do |product, index|
      next if product.valid?
      
      product.errors.add(:row_id, index)
      
      product.errors.each do |error|
        errors.import(error, { attribute: "products" })
      end
    end
  end

it returns:

"products":[0,"can't be blank","must be greater than 0",1]

why it's plain array and keys are missing?

@lulalala
Copy link
Contributor Author

@lulalala lulalala commented Feb 10, 2021

@thefaded Hi there! Sorry for the late reply.

The reason is that you tried to add non-message information into the messages hash, so Rails treats it as a message in 6.1. It suits better to be stored in details hash.

Based on your use case, I think the most Railsey way would be to utilize index_errors

If you really want to roll your own solution, I would suggest to add the index into the error options, e.g.:

  def all_products_are_valid
    products.each.with_index do |product, index|
      next if product.valid?
      
      product.errors.each do |product_error|
        product_error.options[:row_id] = index
        errors.import(product_error, { attribute: "products" })
      end
    end
  end

When you output the errors, you would have write code to output the error details and messages together. I would monkey-patch like this:

module ActiveModel
  class Errors
    def details_with_message
      hash = group_by_attribute.transform_values do |errors|
        errors.map do |error|
          error.details.tap do |details|
            details[:message] = error.message
          end
        end
      end
    end
  end
end

The new details_with_message method would then output all the things and you can get the message and row_id as wish.

@lulalala
Copy link
Contributor Author

@lulalala lulalala commented Feb 10, 2021

@alaarab

Have you considered monkey patching? You can override the Error#initialize class, generate the message when called and store that as an instance variable. You then have to override message method to just return that message. Fingers crossed that this may break something else, but should still be fixable.

@alaarab
Copy link

@alaarab alaarab commented Feb 10, 2021

@lulalala I appreciate your response. I have already handled this in my use case without monkey patching. My solution was to create a module in app/models/concerns called last_validatable.rb:

 # This module adds error messages directly after validation to an attr_accessor on the model
module LastValidatable
  extend ActiveSupport::Concern

  included do
    attr_accessor :last_full_error_messages
    after_validation :populate_last_full_error_messages

    def populate_last_full_error_messages
      self.last_full_error_messages = self.errors.full_messages
    end
  end
end

Then on my models where I needed this functionality I simply included them with the following:

include LastValidatable

And finally, from my views I use this attr_accessor to display my errors from:

  <%= f.error_notification %>
  <%= f.error_notification message: f.object.last_full_error_messages.uniq.join("<br/>") if f.object.last_full_error_messages.present? %>

With this solution, I know I am not destroying any other functionality, just adding one step in my callback chain which I believe I am comfortable with at this time.

Thank you again for responding.

coffeejunk added a commit to coffeejunk/jsonapi.rb that referenced this pull request Feb 14, 2021
Starting with Rails 6.1 ActiveModel::Error is an actual class:

> Active Model's errors are now objects with an interface that allows
> your application to more easily handle and interact with errors thrown
> by models. The feature[1] includes a query interface, enables more
> precise testing, and access to error details.
>
> [1] rails/rails#32313

As a result of this `resource.details` looks slightly different than in
previous versions and notably doesn't contain `:message` anymore, if
`object.errors.add(:something, message: 'some error')` was used to
specify a validation error.
https://github.com/rails/rails/blob/2a7ff0a5f54979b14b19f827c99295297dda411d/activemodel/lib/active_model/error.rb#L149

From the test suite:
```
note.errors.add(:title, message: 'has typos') if note.errors.key?(:title)
```

Rails 6.0:
```
{
  :title=>[{:error=>:invalid, :value=>"BAD_TITLE"},
           {:error=>{:message=>"has typos"}}],
  :quantity=>[{:error=>:less_than, :value=>109, :count=>100}]
}
```

Rails 6.1:
```
{
  :title=>[{:error=>:invalid, :value=>"BAD_TITLE"},
           {:error=>:invalid}],
  :quantity=>[{:error=>:less_than, :value=>100, :count=>100}]
}
```

The patch addresses this change by merging the error.message into it's detail.
coffeejunk added a commit to coffeejunk/jsonapi.rb that referenced this pull request Feb 14, 2021
Starting with Rails 6.1 ActiveModel::Error is an actual class:

> Active Model's errors are now objects with an interface that allows
> your application to more easily handle and interact with errors thrown
> by models. The feature[1] includes a query interface, enables more
> precise testing, and access to error details.
>
> [1] rails/rails#32313

As a result of this `resource.details` looks slightly different than in
previous versions and notably doesn't contain `:message` anymore, if
`object.errors.add(:something, message: 'some error')` was used to
specify a validation error.
https://github.com/rails/rails/blob/2a7ff0a5f54979b14b19f827c99295297dda411d/activemodel/lib/active_model/error.rb#L149

From the test suite:
```
note.errors.add(:title, message: 'has typos') if note.errors.key?(:title)
```

Rails 6.0:
```
{
  :title=>[{:error=>:invalid, :value=>"BAD_TITLE"},
           {:error=>{:message=>"has typos"}}],
  :quantity=>[{:error=>:less_than, :value=>109, :count=>100}]
}
```

Rails 6.1:
```
{
  :title=>[{:error=>:invalid, :value=>"BAD_TITLE"},
           {:error=>:invalid}],
  :quantity=>[{:error=>:less_than, :value=>100, :count=>100}]
}
```

The patch addresses this change by merging the error.message into its detail.
stas added a commit to stas/jsonapi.rb that referenced this pull request Feb 14, 2021
Starting with Rails 6.1 ActiveModel::Error is an actual class:

> Active Model's errors are now objects with an interface that allows
> your application to more easily handle and interact with errors thrown
> by models. The feature[1] includes a query interface, enables more
> precise testing, and access to error details.
>
> [1] rails/rails#32313

As a result of this `resource.details` looks slightly different than in
previous versions and notably doesn't contain `:message` anymore, if
`object.errors.add(:something, message: 'some error')` was used to
specify a validation error.
https://github.com/rails/rails/blob/2a7ff0a5f54979b14b19f827c99295297dda411d/activemodel/lib/active_model/error.rb#L149

From the test suite:
```
note.errors.add(:title, message: 'has typos') if note.errors.key?(:title)
```

Rails 6.0:
```
{
  :title=>[{:error=>:invalid, :value=>"BAD_TITLE"},
           {:error=>{:message=>"has typos"}}],
  :quantity=>[{:error=>:less_than, :value=>109, :count=>100}]
}
```

Rails 6.1:
```
{
  :title=>[{:error=>:invalid, :value=>"BAD_TITLE"},
           {:error=>:invalid}],
  :quantity=>[{:error=>:less_than, :value=>100, :count=>100}]
}
```

The patch addresses this change by merging the error.message into its detail.
@bigforcegun
Copy link

@bigforcegun bigforcegun commented Mar 10, 2021

@lulalala

Can you please provide an extended example or documentation how to use import method?

What shall I do if I need nested errors structure like this?

{
   "title": level_1_error,
   "items": {
      "item_1": {level_2_error}
   }
}

Rails 6.0

class NestedPerson
  # Required dependency for ActiveModel::Errors
  extend ActiveModel::Naming

  def initialize
    @errors = ActiveModel::Errors.new(self)
  end

  attr_accessor :items
  attr_reader :errors

  def validate!
    errors.add(:items, {"item_1": "some_error"})
    errors.add(:items, {"item_2": "some_error"})
  end
end
[2] pry(main)> q = NestedPerson.new
=> #<NestedPerson:0x000056385c816b50 @errors=#<ActiveModel::Errors:0x000056385c816ab0 @base=#<NestedPerson:0x000056385c816b50 ...>, @details={}, @messages={}>>
[3] pry(main)> q.validate!
=> [{:item_1=>"some_error"}, {:item_2=>"some_error"}]
[4] pry(main)> q.errors
=> #<ActiveModel::Errors:0x000056385c816ab0
 @base=#<NestedPerson:0x000056385c816b50 @errors=#<ActiveModel::Errors:0x000056385c816ab0 ...>>,
 @details={:items=>[{:error=>{:item_1=>"some_error"}}, {:error=>{:item_2=>"some_error"}}]},
 @messages={:items=>[{:item_1=>"some_error"}, {:item_2=>"some_error"}]}>
[5] pry(main)> q.errors.as_json
=> {:items=>[{:item_1=>"some_error"}, {:item_2=>"some_error"}]}
[6] pry(main)>

Rails 6.1

class NestedPerson
  # Required dependency for ActiveModel::Errors
  extend ActiveModel::Naming

  def initialize
    @errors = ActiveModel::Errors.new(self)
  end

  attr_accessor :items
  attr_reader :errors

  def validate!
    errors.add(:items, { "item_1": "some_error" })
    errors.add(:items, { "item_2": "some_error" })
  end

  # The following methods are needed to be minimally implemented

  def read_attribute_for_validation(attr)
    send(attr)
  end

  def self.human_attribute_name(attr, options = {})
    attr
  end

  def self.lookup_ancestors
    [self]
  end

end
[7] pry(main)> q = NestedPerson.new
=> #<NestedPerson:0x0000564c806e4128 @errors=#<ActiveModel::Errors:0x0000564c806e4100 @base=#<NestedPerson:0x0000564c806e4128 ...>, @errors=[]>>
[8] pry(main)> q.validate!
=> #<ActiveModel::Error attribute=items, type=invalid, options={:item_2=>"some_error"}>
[9] pry(main)> q.errors
=> #<ActiveModel::Errors:0x0000564c806e4100
 @base=#<NestedPerson:0x0000564c806e4128 @errors=#<ActiveModel::Errors:0x0000564c806e4100 ...>>,
 @errors=
  [#<ActiveModel::Error attribute=items, type=invalid, options={:item_1=>"some_error"}>,
   #<ActiveModel::Error attribute=items, type=invalid, options={:item_2=>"some_error"}>]>
[10] pry(main)> q.errors.as_json
=> {:items=>["is invalid", "is invalid"]}

@lulalala
Copy link
Contributor Author

@lulalala lulalala commented Mar 11, 2021

@bigforcegun

I think you are trying similar things, wanting to add multiple errors to the has_many association with index.

Could you read #32313 (comment) and see if that helps? Thanks!

mehulagg pushed a commit to mehulagg/gitlab that referenced this pull request Apr 23, 2021
Modal errors as objects are introduced:
rails/rails#32313

model.errors.first returns ActiveModel::Error object
that's why model.errors.first[1] doesn't work in Rails 6.1

We need a way that works both for 6.1 and 6.0 in order to
introduce changes gradually:

model.errors.values.first works for both versions.

Even though treating errors as a hash is deprecated it works
so we can introduce the changes in 6.0 and then fix the
deprecations when we're on 6.1

(cherry picked from commit b5ecc309314429040921233d4a6216655fede089)
pixeltrix added a commit to pixeltrix/globalize that referenced this pull request May 2, 2021
In rails/rails#32313 the method signature of `Errors#add` was changed
to keyword arguments instead of an options hash. In Ruby 3.0 this now
fails with an ArgumentError so we need to expand the hash.
pixeltrix added a commit to pixeltrix/globalize that referenced this pull request May 12, 2021
In rails/rails#32313 the method signature of `Errors#add` was changed
to keyword arguments instead of an options hash. In Ruby 3.0 this now
fails with an ArgumentError so we need to expand the hash.
mehulagg pushed a commit to mehulagg/gitlab that referenced this pull request May 14, 2021
Modal errors as objects are introduced:
rails/rails#32313

model.errors.first returns ActiveModel::Error object
that's why model.errors.first[1] doesn't work in Rails 6.1

We need a way that works both for 6.1 and 6.0 in order to
introduce changes gradually:

model.errors.values.first works for both versions.

Even though treating errors as a hash is deprecated it works
so we can introduce the changes in 6.0 and then fix the
deprecations when we're on 6.1


(cherry picked from commit b5ecc309314429040921233d4a6216655fede089)
mehulagg pushed a commit to mehulagg/gitlab that referenced this pull request May 18, 2021
Modal errors as objects are introduced:
rails/rails#32313

model.errors.first returns ActiveModel::Error object
that's why model.errors.first[1] doesn't work in Rails 6.1

We need a way that works both for 6.1 and 6.0 in order to
introduce changes gradually:

model.errors.values.first works for both versions.

Even though treating errors as a hash is deprecated it works
so we can introduce the changes in 6.0 and then fix the
deprecations when we're on 6.1
lulalala added a commit to lulalala/rubocop-rails that referenced this pull request May 24, 2021
These are deprecated in Rails 6.1 and will be removed in Rails 7.
See rails/rails#32313 for details.

The cop acts in two modes:

For files under `/models` directory, any `errors` call,
whether with receiver or not, will be checked.
For general files, only `errors` calls with receivers will be checked.

E.g. `errors[:bar] = []` is without receiver.
It will record an offense if it is a model file.
It will not record an offense if it is other general fie.

This is to reduce false-positives,
since other classes may also have a `errors` method.
lulalala added a commit to lulalala/rubocop-rails that referenced this pull request May 24, 2021
These are deprecated in Rails 6.1 and will be removed in Rails 7.
See rails/rails#32313 for details.

The cop acts in two modes:

For files under `/models` directory, any `errors` call,
whether with receiver or not, will be checked.
For general files, only `errors` calls with receivers will be checked.

E.g. `errors[:bar] = []` is without receiver.
It will record an offense if it is a model file.
It will not record an offense if it is other general fie.

This is to reduce false-positives,
since other classes may also have a `errors` method.
lulalala added a commit to lulalala/rubocop-rails that referenced this pull request May 28, 2021
These are deprecated in Rails 6.1 and will be removed in Rails 7.
See rails/rails#32313 for details.

The cop acts in two modes:

For files under `/models` directory, any `errors` call,
whether with receiver or not, will be checked.
For general files, only `errors` calls with receivers will be checked.

E.g. `errors[:bar] = []` is without receiver.
It will record an offense if it is a model file.
It will not record an offense if it is other general fie.

This is to reduce false-positives,
since other classes may also have a `errors` method.
lulalala added a commit to lulalala/rubocop-rails that referenced this pull request Jun 5, 2021
These are deprecated in Rails 6.1 and will be removed in Rails 7.
See rails/rails#32313 for details.

The cop acts in two modes:

For files under `/models` directory, any `errors` call,
whether with receiver or not, will be checked.
For general files, only `errors` calls with receivers will be checked.

E.g. `errors[:bar] = []` is without receiver.
It will record an offense if it is a model file.
It will not record an offense if it is other general fie.

This is to reduce false-positives,
since other classes may also have a `errors` method.
lulalala added a commit to lulalala/rubocop-rails that referenced this pull request Jun 5, 2021
These are deprecated in Rails 6.1 and will be removed in Rails 7.
See rails/rails#32313 for details.

The cop acts in two modes:

For files under `/models` directory, any `errors` call,
whether with receiver or not, will be checked.
For general files, only `errors` calls with receivers will be checked.

E.g. `errors[:bar] = []` is without receiver.
It will record an offense if it is a model file.
It will not record an offense if it is other general fie.

This is to reduce false-positives,
since other classes may also have a `errors` method.
lulalala added a commit to lulalala/rubocop-rails that referenced this pull request Jun 9, 2021
These are deprecated in Rails 6.1 and will be removed in Rails 7.
See rails/rails#32313 for details.

The cop acts in two modes:

For files under `/models` directory, any `errors` call,
whether with receiver or not, will be checked.
For general files, only `errors` calls with receivers will be checked.

E.g. `errors[:bar] = []` is without receiver.
It will record an offense if it is a model file.
It will not record an offense if it is other general fie.

This is to reduce false-positives,
since other classes may also have a `errors` method.
lulalala added a commit to lulalala/rubocop-rails that referenced this pull request Jul 18, 2021
These are deprecated in Rails 6.1 and will be removed in Rails 7.
See rails/rails#32313 for details.

The cop acts in two modes:

For files under `/models` directory, any `errors` call,
whether with receiver or not, will be checked.
For general files, only `errors` calls with receivers will be checked.

E.g. `errors[:bar] = []` is without receiver.
It will record an offense if it is a model file.
It will not record an offense if it is other general fie.

This is to reduce false-positives,
since other classes may also have a `errors` method.
lulalala added a commit to lulalala/rubocop-rails that referenced this pull request Jul 18, 2021
These are deprecated in Rails 6.1 and will be removed in Rails 7.
See rails/rails#32313 for details.

The cop acts in two modes:

For files under `/models` directory, any `errors` call,
whether with receiver or not, will be checked.
For general files, only `errors` calls with receivers will be checked.

E.g. `errors[:bar] = []` is without receiver.
It will record an offense if it is a model file.
It will not record an offense if it is other general fie.

This is to reduce false-positives,
since other classes may also have a `errors` method.
lulalala added a commit to lulalala/rubocop-rails that referenced this pull request Jul 18, 2021
These are deprecated in Rails 6.1 and will be removed in Rails 7.
See rails/rails#32313 for details.

The cop acts in two modes:

For files under `/models` directory, any `errors` call,
whether with receiver or not, will be checked.
For general files, only `errors` calls with receivers will be checked.

E.g. `errors[:bar] = []` is without receiver.
It will record an offense if it is a model file.
It will not record an offense if it is other general fie.

This is to reduce false-positives,
since other classes may also have a `errors` method.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet