我的模型有一个字符串字段(很短),并将其存储在数据库中,这是很好。但我希望它始终返回一个符号而不是字符串,而且,我想为该字符串属性分配一个符号。我现在所做的不起作用。
class MyModel < ActiveRecord::Base
attr_accessible :attr1
def attr1
# self.try(:attr1).to_sym # how to return symbol?
end
def attr1= value
# super.attr1.to_sym # doesn't work either
end
end
我怎样才能达到这个目标?
我认为你只需要覆盖 getter,如果它是一个字段,setter 可能工作得很好。
class MyModel < ActiveRecord::Base
def attr1
attributes['attr1']&.to_sym
end
end
或者您也可以创建一个序列化器:
class SymbolSerializer
def self.dump(obj)
return unless obj
obj.to_s
end
def self.load(text)
return unless text
text.to_sym
end
end
然后在你的模型中:
class MyModel < ActiveRecord::Base
serialize :attr1, SymbolSerializer
end
如果您需要在多列或不同模型中执行此操作,我建议概括解决方案:
class MyModel < ActiveRecord::Base
include Concerns::Columnable
treat_as_symbols :attr1
end
module Concerns::Columnable
extend ActiveSupport::Concern
included do
def self.treat_as_symbols *args
args.each do |column|
define_method "#{column}" do
read_attribute(column.to_sym).to_sym
end
end
end
end
end
attribute
方法
首先我们需要创建一个自定义的 ActiveRecord::Type,在本例中继承自 ActiveModel::Type::String。这符合文档中扩展现有类型/继承 ActiveModel::Type::Value 的建议。
# app/lib/core_ext/active_record/type/symbol.rb
module ActiveRecord
module Type
class Symbol < ::ActiveModel::Type::String
def deserialize(obj)
super&.to_sym
end
# defined by ActiveModel::Type::String and we do not need to override for this example
# def serialize; end
end
end
end
然后我们需要注册这个自定义类型:
# config/initializers/active_record.rb
# Users may also define their own custom types, as long as they respond to the methods defined on the value type.
# The method deserialize or cast will be called on your type object, with raw input from the database or from your
# controllers. See ActiveModel::Type::Value for the expected API.
# It is recommended that your type objects inherit from an existing type, or from ActiveRecord::Type::Value
# https://api.rubyonrails.org/classes/ActiveRecord/Attributes/ClassMethods.html#method-i-attribute
require "./app/lib/core_ext/active_record/type/symbol"
ActiveRecord::Type.register(:symbol, ActiveRecord::Type::Symbol)
现在我们可以按如下方式设置符号类型:
class MyModel < ApplicationRecord
attribute :attr1, :symbol
end
示例
instance = MyModel.new(attr1: "string")
instance # => #<MyModel:0x0000ffffacaa19d0 id: 1, attr1: :string>
instance.attr1 # => :string
instance.inspect # => "#<MyModel id: 1, attr1: :string>"
instance.attributes # => {"id"=>1, "attr1"=>:string }