I have a model that can have various types that will affect the fields being used. I'd like to remove the unused fields from the output. Currently, this works:
attribute :field1, if: :is_type1?
attribute :field2, if: :is_type1?
attribute :field3, if: :is_type2?
attribute :field4 # always shown
The thing is I have a lot of attributes and this can become tedious and hard to maintain especially when a field can be used by some but not all of the types. I know that maybe the modelization could be changed to have multiple models and thus multiple serializers but this not something I cannot afford right now so I'm looking for another solution.
I imagined 2 ways of doing this: either having some kind of block to define attributes like:
given -> { object.type == 1 } do
attributes :field1, :field2
end
given -> { object.type == 2 } do
attributes :field3
end
attribute :field4
Or using some generic method in if:
everywhere. For that matter, I already had defined in my model the fields that apply to each type:
def allowed_attr
allowed_attr = {
field1: false,
field2: false,
field3: false
}
case type
when 1
allowed_attr[:field1] = true
allowed_attr[:field2] = true
when 2
allowed_attr[:field3] = true
end
allowed_attr
end
What i would like to do in my serializer then is something like that:
attribute :field1, if: -> { allowed(attribute_name) }
attribute :field2, if: -> { allowed(attribute_name) }
attribute :field3, if: -> { allowed(attribute_name) }
attribute :field4, if: -> { allowed(attribute_name) }
def allowed(attr)
object.allowed_attr[attr] != false # allows everything that is not precisely set to false
end
The thing is I don't seem to be able to access the field currently being tested (attribute_name
)
Is there some way to do what I wish that I have overlooked ?
EDIT
Here's the solution I used based on Omnigazer's answer.
[
:field1
[:field1_attr, :field1],
[:field2, Proc.new { object.field1.present? }]
].each do |attr|
if attr.kind_of? Array
name = attr.shift
if attr[0].kind_of? Symbol
allowed = attr.shift
end
if attr[0].kind_of? Proc
cond = attr.shift
end
end
name ||= attr
allowed ||= name
cond ||= Proc.new { true }
attribute name, if: -> { instance_eval(&cond) && object.allowed_attribute?(allowed) }
end
You could do something like this:
[:field1, :field2, :field3, :field4].each do |attribute_name|
attribute attribute_name, if: -> { allowed(attribute_name) }
end