Reputation: 13
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
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
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