I'd recommend handling it much the same way I recommend handling users. Create a var containing the rules and state of the rule. And have it loop using with_items. Something like:
ufw_rules:
- port: 22
rule: allow
proto: tcp
- port: 80
delete: yes
rule: allow
proto: tcp
and then a task like:
ufw:
port: "{{ item.port }}"
rule: "{{ item.rule }}"
proto: "{{ item.proto }}"
delete: "{{ item.delete|default(omit) }}"
with_items: "{{ ufw_rules }}"
In the above, if delete is specified it is used, otherwise, if missing that param is omitted. This is effectively how we handle this today.