-
-
Notifications
You must be signed in to change notification settings - Fork 276
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
Add RSpec/FactoryBot/AssociationStyle
cop
#1414
Conversation
It seems that over time, all the three progressed. I was still believing that the implicit way didn't allow specifying Personally, I strongly prefer the inline definition, for three reasons:
The downside is that it's the most verbose out of the three in most of the cases.
Is there anything else that I'm missing? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good as is. Up to you if you tend to keep it like that, and leave improvements for follow-up PRs/tickets.
The only thing left to do is to run it against real-world-rspec
and see which style is most frequently used in the wild to minimize the impact and follow what people really use. I can run this for you if you like.
author do | ||
association :user | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could be written as implicit author factory: :user
, so I'd count this as an offence.
It's the inline style that we don't detect, but not really "inline" 😄
The
The
for e.g.: FactoryBot.define do
factory :like, class: Carto::Like do
end
end factory 'valid site' do
# after(:build) { |valid_site| valid_site.stubs(:valid?).returns(true) }
end |
Implicit:
Explicit:
Going with the implicit as the default enforced style seems reasonable 👍 |
82ba67f
to
3bd988f
Compare
As noted in the documentation, attributes defined by inline-style always appears with # implicit
FactoryBot.define do
factory :article do
user
end
end
FactoryBot.attributes_for(:article) #=> {} # explicit
FactoryBot.define do
factory :article do
association :user
end
end
FactoryBot.attributes_for(:article) #=> {} # inline
FactoryBot.define do
factory :article do
user { association :user }
end
end
FactoryBot.attributes_for(:article) #=> {:user => nil}
For that reason, it would be difficult to safely say that this is an offense 🤔 My personal preference is to use inline-style only when I need it and not otherwise. If I always use inline-style, it makes difficult to infer from the code whether I am doing so because inline-style is necessary in the case or not. If there seems to be a certain number of people who want to use the inline-style all the time, it might be nice to have a style in this cop that always prefers the inline-style. The downside is that it is quite difficult to autocorrect from inline-style to the other styles for the reasons mentioned above. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A couple of cosmetic suggestions
2d2594a
to
417a51d
Compare
|
I can also think of |
It seems that the implicit style does not allow such trait usage, so I need to fix # frozen_string_literal: true
require 'bundler/inline'
gemfile do
source 'https://rubygems.org'
gem 'factory_bot'
end
FactoryBot.define do
factory :article do
trait :active do
active { true }
end
end
factory :comment do
article :active
end
end
Instead, it can be written by using # frozen_string_literal: true
require 'bundler/inline'
gemfile do
source 'https://rubygems.org'
gem 'activerecord', '~> 7.0.0'
gem 'factory_bot'
gem 'sqlite3'
end
require 'active_record'
require 'logger'
require 'minitest/autorun'
ActiveRecord::Base.establish_connection(
adapter: 'sqlite3',
database: ':memory:'
)
ActiveRecord::Schema.define do
create_table :articles, force: true do |t|
t.boolean :active, default: false
end
create_table :comments, force: true do |t|
t.references :article
end
end
class Article < ActiveRecord::Base
end
class Comment < ActiveRecord::Base
belongs_to :article
end
FactoryBot.define do
factory :article do
trait :active do
active { true }
end
end
factory :comment do
article factory: [:article, :active]
end
end
class FactoryTest < Minitest::Test
def test_association
assert ::FactoryBot.create(:comment).article.active
end
end
|
I might be talking nonsense, but as an alternative to article factory: [:article, :active] would it be possible to write it as article traits: [:active] Which one would you prefer? |
I feel you. I actually tried that example before posting the previous comment too, but I couldn't use Perhaps only I created the following Pull Request on thoughtbot/factory_bot: |
85aa570
to
a5ca5b4
Compare
config/default.yml
Outdated
NonImplicitAssociationMethodNames: | ||
- association | ||
- skip_create | ||
- traits_for_enum |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this have to be user configurable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Certainly there is no need to make these default values removable. The main reason why I have this config value is for Global sequences.
Factory.define do
sequence(:email) { |n| "person#{n}@example.com" }
factory :user do
email
end
end
9a6b052
to
889ee79
Compare
2c8aaed
to
fa28f48
Compare
fa28f48
to
957caf9
Compare
# # good (defined in NonImplicitAssociationMethodNames) | ||
# skip_create |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think of using something that looks like an global sequence attribute call here, e.g. email
?
# # good (defined in NonImplicitAssociationMethodNames) | |
# skip_create | |
# # good (defined in NonImplicitAssociationMethodNames) | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good 👍
Besides, now that skip_create
is set by constant instead of config, it is strange that this value is used as an example here.
74abfcc
to
7666577
Compare
7666577
to
007543f
Compare
@r7kamura Would you re-target this to |
Recreated on rubocop-factory_bot repo: |
In FactoryBot, there are 2 ways to define associations.
These styles are documented at the following section:
(Stricyly speaking, there is also inline style, but it behaves differently from the above 2 styles.)
It would be nice to have a cop for consistent use of only one of the styles. This Pull Request has been created for this purpose.
Before submitting the PR make sure the following are checked:
master
(if not - rebase it).CHANGELOG.md
if the new code introduces user-observable changes.bundle exec rake
) passes (be sure to run this locally, since it may produce updated documentation that you will need to commit).If you have created a new cop:
config/default.yml
.Enabled: pending
inconfig/default.yml
.Enabled: true
in.rubocop.yml
.VersionAdded
indefault/config.yml
to the next minor version.If you have modified an existing cop's configuration options:
VersionChanged
inconfig/default.yml
to the next major version.