ActiveRecord Virtual Attributes treaded as a record attributes

前端 未结 6 1369
小鲜肉
小鲜肉 2021-01-02 04:54

I am running into a problem with to_json not rendering my virtual attributes

class Location < ActiveRecord::Base
    belongs_to :event
    before_create :g         


        
相关标签:
6条回答
  • 2021-01-02 05:23

    I tried François Beausoleil's answer and got it to work after modifying to_json to as_json

    def as_json(options={})
      options[:methods] ||= []
      options[:methods] << :class_to_s
      super(options)
    end
    
    0 讨论(0)
  • 2021-01-02 05:24

    Simply implement #to_json yourself then:

    class Location < ActiveRecord::Base
      def to_json(options={})
        options[:methods] ||= []
        options[:methods] << :event_oid
        super(options)
      end
    end
    
    0 讨论(0)
  • 2021-01-02 05:30

    how about to_json(:methods => [:event_oid]), does that work?

    0 讨论(0)
  • 2021-01-02 05:30

    An old question but what OP asked is now possible and simple once you know how. Here a complete runnable example but everything you need is in the class Location. The attribute statement expands the attributes of the model and the after_initialize takes care of the assignment of the value.

    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">
    
    0 讨论(0)
  • 2021-01-02 05:39

    You want to modify the attributes hash. There's a little extra code here to ensure the attributes you care about are ready to be used with to_json or another method that depends on attributes on object load.

    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 and a lot of other methods that generate lists of things based on an objects attributes. Which is populated on object initialization with database tables and names, unfortunately instance variables do not update this hash.

    P.S. this isn't very DRY if you have a number of attributes you want to use in this manner. You could use an Array of symbols, deterministic method names and a class_eval block to apply this process to multiple symbols at once.

    Warning

    We're messing with rails internals here. There's no telling how it could cause other things to fail. I haven't tested more than save and to_json, both of which work when the attribute hash contains keys that are not also column names. So use it at your own risk.

    0 讨论(0)
  • 2021-01-02 05:46
    location.to_json(:methods => :event_oid)
    

    As explained here: http://apidock.com/rails/ActiveRecord/Serialization/to_json

    In a controller simply use:

    format.json { render json: @location.to_json(:methods => :event_oid) }
    
    0 讨论(0)
提交回复
热议问题