Reputation: 18037
I have a common pattern or repeated code that I'd like to DRY up in my ActiveAdmin views. I'm using arbre components to render as much of my views as I can and I'd like to keep it that way if possible (i.e. I don't really want to convert to straight up HTML in the normal fashion -- I'm trying to understand the arbre way here). Here's the code I'd like to DRY up:
clients.in_groups_of(3).each do |clients_group|
columns do
clients_group.compact.each do |client|
column do
panel client.name do
# ...
end
end
end
end
end
After reading through the documentation in the arbre gem, I started to try to create my own, custom arbre component. But I was quickly forced to realize that I have no idea how to satisfy arbre. I couldn't figure out how to pass my local variables into the block. For example:
# config/initializers/active_admin.rb
module ActiveAdmin
module Views
class ClientsBreakdown < ActiveAdmin::Component
builder_method :clients_breakdown
def build(clients, attributes = {})
group_size = attributes.delete(:in_groups_of) { 3 }
clients.in_groups_of(group_size).each do |clients_group|
columns do
clients_group.compact.each do |client|
column do
panel client.name do
super(attributes) # Doesn't seem to matter where this `super` call
# is, but I do want to be able to pass `client`
# into the `clients_breakdown` block here
# yield(client) # -- I've also tried adding this.
end
end
end
end
end
end
end
end
end
Then, calling this in my ActiveAdmin User view might look like:
clients_breakdown(Client.all, in_groups_of: 2) do |client|
ul do
li client.name
end
end
Running the above code results in this error:
UPDATE 2 The exception has changed to this after moving my custom component code into the ActiveAdmin::Views
module.
My key issue seems to be that I can't just call yield(client)
where I currently have super(attributes)
. But that's an arbre thing so I don't know what to do there to pass the client into the calling block. Is this the right track or is there another way to DRY this up?
I've realized that the call to super
can happen anywhere in the build
method and really has nothing to do with what is output. So even if I move the super(attributes)
call up... I still can't figure out what to put inside of the panel
block so that I can render the rest of my arbre components in there from the call to clients_breakdown
.
Upvotes: 3
Views: 2338
Reputation: 3363
Here is one potential solution.
A few things to note are super(attributes)
should not be called unless
the ClientBreakdown
Arbre component is outputting its own HTML. Arbre components
are generally used to build up HTML from scratch, not necessarily to
compose components.
module ActiveAdmin
module Views
class ClientsBreakdown < ActiveAdmin::Component
builder_method :clients_breakdown
def build(clients, attributes = {})
group_size = attributes.delete(:in_groups_of) { 3 }
clients.in_groups_of(group_size).each do |clients_group|
columns do
clients_group.compact.each do |client|
column do
panel client.name do
yield client
end
end
end
end
end
end
end
end
end
Another approach would be to define helper methods to provide the same
functionality in a module to be included in ActiveAdmin::Views::Pages::Base
.
This is where ActiveAdmin defines its helper methods to build the various views, like attributes_table
.
module ClientsBreakdown
def clients_breakdown(clients, attributes = {})
group_size = attributes.delete(:in_groups_of) { 3 }
clients.in_groups_of(group_size).each do |clients_group|
columns do
clients_group.compact.each do |client|
column do
panel client.name do
yield client
end
end
end
end
end
end
end
# config/initializers/active_admin.rb
ActiveAdmin::Views::Pages::Base.include ClientsBreakdown
Upvotes: 7