Tim Blokdijk
Tim Blokdijk

Reputation: 13

Can I use something along the lines of String#constantize to initialize a Hyperstack::Component?

I have some objects in my DB that I like to render with a dedicated Hyperstack view Component. Lets say my objects have a unique name property from A to J. Now I would like to loop through them with each and render a ComponentA, ComponentB, ComponentC, ... depending on the name of my object, and pass my object as a param to the component.

What I do now is:

DB_Objects.each do |object|
  if    object.name == 'A'
    ComponentA(data: object)
  elsif object.name == 'B'
    ComponentB(data: object)
  elsif object.name == 'C'
    ComponentC(data: object)
  elsif ...

What I want to do is something like:

DB_Objects.each do |object|
  ('Component' + object.name).constantize(data: object)
end

This is pseudo code as you can't give variables to constantize. But it shows what I would like to do.

How can I prevent a manual mapping of a object to its view.

Upvotes: 1

Views: 192

Answers (2)

Mitch VanDuyn
Mitch VanDuyn

Reputation: 2878

Every component class defines a method of the same name as the class. When you say for example

ComponentA(data: object)

you are calling a method named ComponentA that is tied the the ComponentA class.

So to dynamically reference the component you would use the send method:

send('Component' + object.name, data: object)

Alternatively each component class has a class method insert_element which will render an instance of the component class, and insert it into the rendering buffer. For example:

('Component' + object.name).constantize.insert_element(data: object)

I bring this up because while it is longer, you could use it to generalize this idea of yours (which I think is pretty cool)

class ApplicationRecord < ActiveRecord::Base
  def render(opts = {})
    ('Component' + object.name).constantize.insert_element(opts, data: object)
  end
end

Now you can say

some_record.render

Of course to generalize it like this you might want to use something other than name. Anyway you could really have fun with this !

Upvotes: 1

Josh Brody
Josh Brody

Reputation: 5363

Never used HyperStack, but this should give you the right idea.

class Thing < ApplicationRecord
  OBJECT_TYPES = { 'A': 'CommponentA' }.freeze

  def to_component
    @to_component ||= OBJECT_TYPES[self.name].constantize.new(self)
  end 
end 

You could just "Component#{self.name}".constantize.new(self) but I've found that to be rather confusing to other developers when they jump in on a project.

Keep in mind String#constantize will return the actual constant, and not just a string that's constantized (camelcased and what have you) so you can call #new or #call or whatever you want on it.

Upvotes: 2

Related Questions