Rails AR. validate one field, with 4 validators & 2 condition block
validates :inn,
presence: { if: -> { user.is_a?(Client) } },
inn: { if: -> { user.is_a?(Client) } },
uniqueness: { if: -> { user.is_a?(Client) } },
absence: { if: -> { user.is_a?(Department) } }
Could I have some tips on refactoring this?
3 Answers 3
You can try something like this (obviously names can be shorter):
if_user_is_a = ->(klass) { { if: -> { user.is_a?(klass) } } }
validates :inn, presence: if_user_is_a[Client], ..., absence: if_user_is_a[Department]
or
if_user_is_a = ->(klass) { { if: -> { user.is_a?(klass) } } }
if_user_is_a_client = if_user_is_a[Client]
...
validates :inn, presence: if_user_is_a_client, ...
-
\$\begingroup\$ It seems better, but maybe is it something better than that? \$\endgroup\$Alex Antonov– Alex Antonov2014年01月09日 05:34:10 +00:00Commented Jan 9, 2014 at 5:34
-
\$\begingroup\$ It seems there isn't any better than that. Regards! \$\endgroup\$Alex Antonov– Alex Antonov2014年01月21日 23:49:33 +00:00Commented Jan 21, 2014 at 23:49
Why don't you split both conditions into 2 diffrent validations? I think it's cleaner and easier to read (ie more maintenable).
validates :inn, presence: true, uniqueness: true, if: :user_is_client #no idea about that `inn` option on your example
validates :inn, absence: true, if: :user_is_department
def user_is_client
user.is_a?(Client)
end
def user_is_department
user-is_a?(Department)
end
Personally, I prefer to be more verbose some times. Also, I think this way conditions are checked only once each, the other way each condition is checked for each validation since rails has to evaluate all blocks.
You can try to use a method instead of repeat yourself 4 times
Something like:
validates :inn,
presence: { inn_meth { Client } },
inn: { inn_meth { Client } },
uniqueness: { inn_meth { Client} },
absence: { inn_meth{ Department } }
def inn_meth
if: -> { user.is_a?(yield) }
end
inn
as an option ofvalidates
? \$\endgroup\$