I have a Blueprinter serializer with a custom field (see screenshot)
field :score_details do |user|
user.score_details
end
and you can see a Rubocop warning for this block and I can't make it disappear. I read the Rubocop doc : SymbolProc but without success..
To explain in details: I have a User model in which I include a concern in order to calculate a score. In this concern I have 1 method (with no parameter) which returns a simple integer.
Finally, I use this method in my UserSerializer in order to render my score to my frontend.
Here is my include in my User model:
class User < ApplicationRecord
include UserScoresConcern
end
Here is my concern:
module UserScoresConcern
extend ActiveSupport::Concern
included do
def score_details
# this method return 45 for example
calculate_user_score_details
end
end
end
What can I do to fix this warning? Has anyone ever encountered the same issue?
Thanks 🙏
The field method takes a block that will be called with 2 arguments the object and the local_options. See BlockExtractor#extract
Your issue is that your block ignores the fact that 2 arguments are provided and thus Rubocop believes you can use Symbold#to_proc (because it thinks there is only a single argument sent to the block); however if you acknowledge the second argument this warning will go away.
field :score_details do |user,_|
user.score_details
end
Here we acknowledge the second argument using the underscore character _. This is a standard convention to show that we do not intend to use this argument.
Another way to determine the method is calling your block with 2 arguments is to use a lambda instead
field :score_details, &->(user) {user.score_details}
This will result in ArgumentError (wrong number of arguments (given 2, expected 1)) because the lambda is only expecting 1 argument but there are 2 arguments being passed in. This is one of the distinct differences between a standard Proc and a lambda (which is a "special" type of Proc).
The error you experienced Commented Here "wrong number of arguments (given 1, expected 0)" can be easily recreated to show what is actually occurring
def example
yield "10",2
end
example(&:to_s)
ArgumentError (wrong number of arguments (given 1, expected 0))
This because when using Symbol#to_proc in this instance it will evaluate as "10".to_s(2) but String#to_s does not take any arguments just like User#score_details thus causing user.score_details(local_options) to fail in the same fashion.
You just have to write it as
field :score_details, &:score_details
The reason for it is that the & prefix operator takes its argument (in this case, a symbol), calls its to_proc method, ensure it is actually a proc, and then use it as block argument.
For symbols, the to_proc method returns a one-argument proc that is equivalent to the __send__ method on the argument. That is:
# these are functionally equivalent:
:my_symbol.to_proc
->(arg) { arg.__send__(:my_symbol) }
->(arg) { arg.my_symbol }
The difference is that Symbol#to_proc is arguably more optimized.
I manage to make it work but without a custom field.
I add my method directly into my fields list like that and it works:
fields :email,
:score_details