ruby-on-rails 如何将对象转换为字符串以供ActiveRecord查询使用?

ozxc1zmp  于 2023-01-27  发布在  Ruby
关注(0)|答案(3)|浏览(161)

我有一个User,它有一个Stringemail属性,但是,当我在应用中处理电子邮件时,我发现最好先将它转换为一个(非持久化的)Email对象,如下所示:

class User < ActiveRecord::Base
  def email
    Email.new(self.read_attribute :email)
  end
end

Email#to_sEmail#to_str都被定义为简单的原始字符串(例如foo@bar.com),因此无论客户端处理的是Email还是String,通常都是非常透明的。
这在使用ActiveRecord指定属性时非常有效:

> email = Email.new('foo@bar.com')
> user.email = email

ActiveRecord知道email属性是一个字符串,并相应地转换Email对象,但令人费解的是,它在查询数据库时并没有这样做:

> email = Email.new('foo@bar.com')
> User.find_by email: email
ActiveRecord::StatementInvalid: can't cast Email to string

当然,我可以打电话

> User.find_by email: email.to_s

但是有没有办法让这种强制转换自动发生呢?

ig9co6j1

ig9co6j11#

This is the responsible object,用于在ActiveModel中将对象强制转换为字符串。请看这里的serialize方法:它没有处理Email的案例。
您可以通过扩展类来添加一个:

module EmailSupport
  def serialize(value)
    case value
    when Email then value.to_s
    else super
    end
  end
end

ActiveModel::Type::ImmutableString.include(EmailSupport)

User.find_by email: Email.new('foo@example.org')
vd2z7a6w

vd2z7a6w2#

您可以重写模型中的getter方法以强制转换并返回字符串。

jv4diomz

jv4diomz3#

我经常遇到这个问题,所以我为T::Enum添加了这个

# typed: true
module TEnumSupport
  def serialize(value)
    case value
    when T::Enum
      value.serialize
    else
      super
    end
  end
end

ActiveModel::Type::ImmutableString.include(TEnumSupport)

相关问题