【问题标题】:ActiveRecord Virtual Attributes treaded as a record attributesActiveRecord 虚拟属性作为记录属性
【发布时间】:2019-08-22 06:06:02
【问题描述】:

我遇到了 to_json 无法呈现我的虚拟属性的问题

class Location < ActiveRecord::Base
    belongs_to :event
    before_create :generate_oid
    validates_associated :event

    attr_accessor :event_oid

    def event_oid
      @event_oid = event.oid
    end
end

event_oid 不是返回的数组的一部分:

Location.first.attributes

当使用自动将记录属性序列化为 jason 的 to_json 时,这对我来说尤其是一个问题。 to_json 省略了我的虚拟属性。

如何将虚拟属性视为实际实例属性?

编辑:

to_json 只是将我的虚拟属性视为实际属性的方法的一个示例。

【问题讨论】:

    标签: ruby-on-rails activerecord


    【解决方案1】:

    您想修改属性哈希。这里有一些额外的代码来确保您关心的属性可以与 to_json 或其他依赖于对象加载属性的方法一起使用。

    class Location < ActiveRecord::Base
        belongs_to :event
        before_create :generate_oid
        validates_associated :event
    
        after_save :event_oid
    
        attr_accessor :event_oid
    
        def event_oid
          @event_oid = @attributes["event_oid"] = event.oid if event.nil?
        end       
    
        def after_initialize
          event_oid
        end
    
    
    end
    

    to_json 和许多其他基于对象属性生成事物列表的方法。在对象初始化时填充数据库表和名称,不幸的是实例变量不会更新此哈希。

    附:如果您有许多要以这种方式使用的属性,这不是很干。您可以使用符号数组、确定性方法名称和 class_eval 块将此过程一次应用于多个符号。

    警告

    我们在这里搞乱了 Rails 的内部结构。没有人知道它是如何导致其他事情失败的。我只测试了 save 和 to_json,当属性散列包含的键不是列名时,这两种方法都有效。因此,使用它需要您自担风险。

    【讨论】:

    • 谢谢。我一直想知道如何做到这一点。这会派上用场的。
    【解决方案2】:

    to_json(:methods =&gt; [:event_oid]) 怎么样,有用吗?

    【讨论】:

    • 这确实有效,我可能不得不使用它。我只是希望有办法让 ActiveRecord 认为 event_oid 相当于位置表中的一列。
    【解决方案3】:

    然后自己实现#to_json:

    class Location < ActiveRecord::Base
      def to_json(options={})
        options[:methods] ||= []
        options[:methods] << :event_oid
        super(options)
      end
    end
    

    【讨论】:

    • 我希望通过其他方法将虚拟属性视为除 to_json 之外的合法属性。 to\json 只是一个例子。我应该更清楚。
    【解决方案4】:

    我尝试了François Beausoleil's answer 并在将to_json 修改为as_json 后让它工作

    def as_json(options={})
      options[:methods] ||= []
      options[:methods] << :class_to_s
      super(options)
    end
    

    【讨论】:

      【解决方案5】:
      location.to_json(:methods => :event_oid)
      

      这里解释:http://apidock.com/rails/ActiveRecord/Serialization/to_json

      在控制器中只需使用:

      format.json { render json: @location.to_json(:methods => :event_oid) }
      

      【讨论】:

        【解决方案6】:

        一个老问题,但是一旦你知道如何操作,OP 提出的问题现在变得可能和简单。 这是一个完整的可运行示例,但您需要的一切都在类 Location 中。 attribute 语句扩展模型的属性,after_initialize 负责值的分配。

        require 'active_record'  
        
        ActiveRecord::Base.establish_connection(  
          :adapter=> "sqlite3",  
          :database=> ":memory:"  
        )  
        
        ActiveRecord::Schema.define do
          create_table :events do |table|
            table.column :name, :string
          end
          create_table :locations do |table|
            table.column :name, :string
            table.column :event_id, :integer
          end
        end
        
        class Event < ActiveRecord::Base
          has_one :location
        end
        
        class Location < ActiveRecord::Base
          belongs_to :event
          attribute :event_name, :string
        
          after_initialize do
            self.event_name = event.name
          end
        end
        
        Event.create(name: 'Event1')
        Location.create(name: 'Location1', event_id: 1)
        p Model.attribute_names
        p Event.first
        p Event.first.location
        
        #["id", "name", "event_id", "event_name"]
        #<Event id: 1, name: "Event1">
        #<Location id: 1, name: "Location1", event_id: 1, event_name: "Event1">
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-04-29
          相关资源
          最近更新 更多