将模型属性视为符号

问题描述 投票:0回答:3

我的模型有一个字符串字段(很短),并将其存储在数据库中,这是很好。但我希望它始终返回一个符号而不是字符串,而且,我想为该字符串属性分配一个符号。我现在所做的不起作用。

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

我怎样才能达到这个目标?

ruby-on-rails ruby
3个回答
9
投票

我认为你只需要覆盖 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

2
投票

如果您需要在多列或不同模型中执行此操作,我建议概括解决方案:

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

0
投票

我认为还有另一种方法使用 ActiveRecord 的

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 }
© www.soinside.com 2019 - 2024. All rights reserved.