Shao Kahn
Shao Kahn

Reputation: 77

Ruby, how to fetch origin object by its memory address or by object_id?

For example, the address is "0x007f6f0954e820" string, how to get actual object?

I write these: in GymsController

class GymsController < ApplicationController
  @@gyms = Array.new
  def private_page
    ...
    cookies.permanent[:gyms] = JSON.generate(@@gyms << @page)
  end
end

and in history.html.slim

- content_for :title, "History"
- breadcrumb :history
= stylesheet_link_tag 'application'

.outer
  main.privacy-index
    .content-wrapper
      h1.headline2 History一覧
      - JSON.parse(cookies.permanent[:gyms]).reverse.each do |value|
        = (value.to_s.split(":").last)[0..-2].inspect
        br

(value.to_s.split(":").last)[0..-2].inspect is "0x007f6f2b587b30" But I wanna get real object, and do like value.title, value.images

Upvotes: 0

Views: 1131

Answers (1)

Jay-Ar Polidario
Jay-Ar Polidario

Reputation: 6603

I do not know a way to "get" the Object by memory address (i.e. your 0x007f6f2b587b30),

but you can "get" the Object by object_id using ObjectSpace._id2ref(OBJECT_ID):

Solution:

Important: this still has inherit issues: see my recommendations below why.

app/controllers/gyms_controller.rb:

class GymsController < ApplicationController
  @@gyms = Array.new
  def private_page
    ...
    gym = @page
    @@gyms << gym
    cookies.permanent[:gyms_object_ids] = gym.object_id
  end
end

your view file:

- content_for :title, "History"
- breadcrumb :history
= stylesheet_link_tag 'application'

.outer
  main.privacy-index
    .content-wrapper
      h1.headline2 History一覧
      - cookies.permanent[:gyms_object_ids]).reverse.each do |gym_object_id|
        - gym = ObjectSpace._id2ref(gym_object_id.to_i)
        = gym.title
        = gym.images
        br

Recommendations:

  • use "class instance-variable" @gyms instead of "class class-variable" @@gyms. See why here.

  • if your @page variable above in your controller, is not a record (being that it does not correspond to any of the models you have, and thus is not saved in the DB), then create a model for it, so that you can save it into the DB, and retrieve these data in your views above through the model's record id, and therefore no longer by object_id.

    This would allow you to solve the following issues of my Solution above:

    • Objects reside in memory, and are subject to garbage collection. Therefore using ObjectSpace._id2ref(OBJECT_ID) is probably gonna fail at times if the Object is already garbage-collected. (see this SO), because ObjectSpace._id2ref above in my solution code runs at different code of execution than where the object is originally defined:

      • one is in the controller where @page object is defined (some request1 / say thread1),
      • the other one is in the view file where ObjectSpace._id2ref() tries to get that object (some request2 / say thread2),
    • in your code, you are using @@gyms = Array.new, which means that @@gyms (being stored in-memory) is not gonna be accessible to other rails processes because memory is not shared between these processes, and to put simply means that @@gyms would have DIFFERENT! values for each of the following processes:

      • rails server #1 (say... unicorn-1 in server1)
      • rails server #2 (say... unicorn-2 in server1)
      • rails server #3 (say... unicorn-3 in server2)
      • background worker process #1 (say... sidekiq-1)
      • background worker process #2 (say... sidekiq-2)
      • etc...

      ...whereas if you instead save the gyms (if possible and if necessary only) into a model and that these gym records belong to a user, then I would imagine doing something like below instead (which will solve these potential differing values above, and will no longer require you to use cookies):

      class Gym < ApplicationRecord
        has_many :gyms_users
        has_many :users, through: :gyms_users
      end
      
      class GymsUser < ApplicationRecord
        belongs_to :gym
        belongs_to :user
        validates :user, uniqueness: { scope: :gym }
      end
      
      class User < ApplicationRecord
        has_many :gyms_users
        has_many :gyms, through: :gyms_users
      end
      

Upvotes: 2

Related Questions