我想創建權威人士政策類,但運營商||并&&不會按預期方式作業(紅寶石2.4.5)。我有以下政策:
def show?
phone_present? && login.physician? \
|| login.administrator? \
|| login.delegate? \
|| (record.id == login.user.id) \
|| (!login.user.registry_card&.admin_actioned? \
&& login.user.has_patient?(record) \
&& login.user.approved_caregiver?)
end
def phone_present?
record.user_demographic.phone.present?
end
我的想法是檢查當前用戶的電話號碼是否存在 - 如果不存在,則應回傳false,然后回傳其余邏輯。原來當第二部分的時候&&:
login.physician? \
|| login.administrator? \
|| login.delegate? \)
回傳true整個運算式true即使phone_present?是`false。這種行為是不可理解的,因為:
2.4.5 :092 > a = false && true
=> false
更奇怪的是,如果我把守衛放在那里,一切都會正常作業:
def show?
return false unless phone_present?
login.physician? \
|| login.administrator? \
|| login.delegate? \
|| (record.id == login.user.id) \
|| (!login.user.registry_card&.admin_actioned? \
&& login.user.has_patient?(record) \
&& login.user.approved_caregiver?)
end
為什么最后一個例子有效而第一個無效?我不想在show?方法內部使用守衛,因為它對我來說似乎不一致。
uj5u.com熱心網友回復:
Ruby 的運算子具有特定的優先順序,因此根據此順序進行系結(類似于數學公式和 ruby?? 中的乘法系結字串比加法系結。
對您的情況很重要的是,&&運營商的系結比||運營商強。因此,您的規則使用以下隱式優先級(通過添加括號表示):
(phone_present? && login.physician?) \
|| (login.administrator?) \
|| (login.delegate?) \
|| (record.id == login.user.id) \
|| (!login.user.registry_card&.admin_actioned? \
&& login.user.has_patient?(record) \
&& login.user.approved_caregiver?)
因此,只有true當有電話號碼并且用戶是醫生時,才會出現第一個選項。對于任何其他選項,電話號碼要求將被忽略。
您可以使用保護或適當的括號來解決此問題。
風格方面,我個人更喜歡使用較小的條件和幾個守衛。這使得各個規則更清晰、更易于推理:
def show?
return false unless phone_present?
return true if login.physician?
return true if login.administrator?
return true if login.delegate?
return true if record.id == login.user.id
return true if !login.user.registry_card&.admin_actioned? && login.user.has_patient?(record) && login.user.approved_caregiver?)
false
end
如果合適,您還可以將一些規則(例如最后一條)添加到一個適當命名的方法中。如上所述,這使得對這些規則的推理變得更加容易,并且還簡化了測驗。
uj5u.com熱心網友回復:
問題在于 Ruby 評估代碼的順序與您期望的方式不同。
一個簡化的例子是
a && b || c
你似乎認為 if a == truethenfalse應該回傳。這意味著您認為它會像這樣評估代碼
a && (b || c)
但這種情況并非如此。由于 Ruby 的運算子優先級,代碼的計算方式如下:
(a && b) || c
這意味著要解決這個問題,您需要告訴 Ruby 您希望它通過添加一些括號來評估與默認值略有不同的代碼。
def show?
phone_present? && (
login.physician? \
|| login.administrator? \
|| login.delegate? \
|| (record.id == login.user.id) \
|| (
!login.user.registry_card&.admin_actioned? \
&& login.user.has_patient?(record) \
&& login.user.approved_caregiver?
)
)
end
順便說一句,大多數條件取決于login和record。我認為當您將這些條件模式化為login. 例如像這樣:
def has_access_to?(record)
physician? || administrator? || delegate? \\
|| (record.id == user.id) \
|| (
!user.registry_card&.admin_actioned? \
&& user.has_patient?(record) \
&& user.approved_caregiver?
)
end
然后您可以在 Pundit 政策中像這樣使用它:
def show?
phone_present? && login.has_access_to?(record)
end
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/403230.html
標籤:
上一篇:使用剪切和中斷將日期分組為周
