如何在 rails 模型中创建 Proc 以防止 DRY? Rails 5.2.1,rails_admin
how to create Proc to prevent DRY in rails model? Rails 5.2.1, rails_admin
class Client < ApplicationRecord
has_many :projects
validates :name, presence: true
validates :phone,
presence: {
message: "Phone or Email can not be blank",
if: Proc.new { |a| a.email.blank? }
},
length: {
minimum: 10,
unless: Proc.new { |a| a.phone.blank? }
}
validates :email,
uniqueness: {
unless: Proc.new { |a| a.email.blank? }
},
presence: {
message: "Phone/Email can't both be blank",
if: Proc.new { |a| a.phone.blank? }
},
format: {
with: URI::MailTo::EMAIL_REGEXP,
unless: Proc.new { |a| a.email.blank? }
}
def phone_blank?
Proc.new { |a| a.phone.blank? }
end
end
如何创建一个方法来替换所有的 Proc?
我刚刚了解 Proc,对此我还不是很熟悉。我尝试使用 :phone_blank 来替换 if:/unless: 之后的所有 proc,但它无法工作。谁能告诉我如何制作 phone_blank?方法可以替换代码中嵌入的所有过程吗?谢谢~
已编辑:
我忘了说我正在使用 rails_admin 作为管理界面。如果我在 if:/unless: 中调用方法,管理面板将显示 Model 'Client' could not be found 然后该模型将从管理面板中消失。我不确定这是 rails_admin 的事情还是 Rails 5 的行为方式。我对 RoR 很陌生,仍然对 Rails 的所有不同版本感到很困惑。...
对于使用方法,不需要 Proc
包装器。
例如
class Client < ApplicationRecord
has_many :projects
validates :name, presence: true
validates :phone,
presence: {
message: "Phone or Email can not be blank",
if: email_blank?
},
length: {
minimum: 10,
unless: phone_blank?
}
validates :email,
uniqueness: {
unless: email_blank?
},
presence: {
message: "Phone/Email can't both be blank",
if: phone_blank?
},
format: {
with: URI::MailTo::EMAIL_REGEXP,
unless: email_blank?
}
def phone_blank?
phone.blank?
end
def email_blank?
email.blank?
end
end
您也可以直接在验证中简单地指定此条件而无需方法或Proc
作为字符串。
例如
class Client < ApplicationRecord
has_many :projects
validates :name, presence: true
validates :phone,
presence: {
message: "Phone or Email can not be blank",
if: 'email.blank?'
},
length: {
minimum: 10,
if: 'phone.present?'
}
validates :email,
uniqueness: {
if: 'email.present?'
},
presence: {
message: "Phone/Email can't both be blank",
if: 'phone.blank?'
},
format: {
with: URI::MailTo::EMAIL_REGEXP,
if: 'email.present?'
}
end
你可以写一个 class 方法,returns 一个 lambda,比如:
def self.blank_field?(field)
->(m) { m.send(field).blank? }
end
然后说这样的话:
validates :phone,
presence: {
message: "Phone or Email can not be blank",
if: blank_field?(:email)
},
length: {
minimum: 10,
unless: blank_field?(:phone)
}
请注意,我们使用 blank_field?
而不是 blank?
,因为 blank?
已被占用,我们不想覆盖它。由于这是一个 "internal" 方法,我们不必担心 public_send
与 send
.
不是直接的答案,但 DRY-ing 的另一种方法是利用 with_options
:
with_options if: -> { email.blank? } do
validates :phone, presence: { message: "Phone or Email can not be blank" }
end
with_options if: -> { phone.blank? } do
validates :email, presence: { message: "Phone/Email can't both be blank" }
end
with_options if: -> { email.present? } do
validates :phone, length: { minimum: 10 }
validates :email, uniqueness: true, format: { with: URI::MailTo::EMAIL_REGEXP }
end
当验证的条件取决于不同的条件时,这尤其有用……比如,类别(如果你有一个 category
列),你可以简单地将这些验证分组with_options
琐事:
你可以把-> { ... }
想成你已经熟悉的Proc.new { ... }
(虽然准确地说它是一个lambda
...这就像一种特殊类型的Proc
。如果您有进一步的兴趣,请参阅这些 SO 帖子: and HERE
class Client < ApplicationRecord
has_many :projects
validates :name, presence: true
validates :phone,
presence: {
message: "Phone or Email can not be blank",
if: Proc.new { |a| a.email.blank? }
},
length: {
minimum: 10,
unless: Proc.new { |a| a.phone.blank? }
}
validates :email,
uniqueness: {
unless: Proc.new { |a| a.email.blank? }
},
presence: {
message: "Phone/Email can't both be blank",
if: Proc.new { |a| a.phone.blank? }
},
format: {
with: URI::MailTo::EMAIL_REGEXP,
unless: Proc.new { |a| a.email.blank? }
}
def phone_blank?
Proc.new { |a| a.phone.blank? }
end
end
如何创建一个方法来替换所有的 Proc? 我刚刚了解 Proc,对此我还不是很熟悉。我尝试使用 :phone_blank 来替换 if:/unless: 之后的所有 proc,但它无法工作。谁能告诉我如何制作 phone_blank?方法可以替换代码中嵌入的所有过程吗?谢谢~
已编辑: 我忘了说我正在使用 rails_admin 作为管理界面。如果我在 if:/unless: 中调用方法,管理面板将显示 Model 'Client' could not be found 然后该模型将从管理面板中消失。我不确定这是 rails_admin 的事情还是 Rails 5 的行为方式。我对 RoR 很陌生,仍然对 Rails 的所有不同版本感到很困惑。...
对于使用方法,不需要 Proc
包装器。
例如
class Client < ApplicationRecord
has_many :projects
validates :name, presence: true
validates :phone,
presence: {
message: "Phone or Email can not be blank",
if: email_blank?
},
length: {
minimum: 10,
unless: phone_blank?
}
validates :email,
uniqueness: {
unless: email_blank?
},
presence: {
message: "Phone/Email can't both be blank",
if: phone_blank?
},
format: {
with: URI::MailTo::EMAIL_REGEXP,
unless: email_blank?
}
def phone_blank?
phone.blank?
end
def email_blank?
email.blank?
end
end
您也可以直接在验证中简单地指定此条件而无需方法或Proc
作为字符串。
例如
class Client < ApplicationRecord
has_many :projects
validates :name, presence: true
validates :phone,
presence: {
message: "Phone or Email can not be blank",
if: 'email.blank?'
},
length: {
minimum: 10,
if: 'phone.present?'
}
validates :email,
uniqueness: {
if: 'email.present?'
},
presence: {
message: "Phone/Email can't both be blank",
if: 'phone.blank?'
},
format: {
with: URI::MailTo::EMAIL_REGEXP,
if: 'email.present?'
}
end
你可以写一个 class 方法,returns 一个 lambda,比如:
def self.blank_field?(field)
->(m) { m.send(field).blank? }
end
然后说这样的话:
validates :phone,
presence: {
message: "Phone or Email can not be blank",
if: blank_field?(:email)
},
length: {
minimum: 10,
unless: blank_field?(:phone)
}
请注意,我们使用 blank_field?
而不是 blank?
,因为 blank?
已被占用,我们不想覆盖它。由于这是一个 "internal" 方法,我们不必担心 public_send
与 send
.
不是直接的答案,但 DRY-ing 的另一种方法是利用 with_options
:
with_options if: -> { email.blank? } do
validates :phone, presence: { message: "Phone or Email can not be blank" }
end
with_options if: -> { phone.blank? } do
validates :email, presence: { message: "Phone/Email can't both be blank" }
end
with_options if: -> { email.present? } do
validates :phone, length: { minimum: 10 }
validates :email, uniqueness: true, format: { with: URI::MailTo::EMAIL_REGEXP }
end
当验证的条件取决于不同的条件时,这尤其有用……比如,类别(如果你有一个 category
列),你可以简单地将这些验证分组with_options
琐事:
你可以把-> { ... }
想成你已经熟悉的Proc.new { ... }
(虽然准确地说它是一个lambda
...这就像一种特殊类型的Proc
。如果您有进一步的兴趣,请参阅这些 SO 帖子: