I am trying to use apotomo
for setting up widgets in my app and have been running into a few issues. I've tried researching, but haven't found anything useful yet. Hopefully, someone might have some experience here.
Here is my setup:
PagesController#show
view is used to display a published version of the page or preview the page for the user. The PagesController#edit
view is used to display the page in "edit" mode w/ forms for each widget, allowing the user to update them as needed.title
, url
, etc).The issue I am running into is displaying each user's customized widget.
For the sake of this question, let's assume I have a single widget "PicturesWidget". I've added the widget to the PagesController
like so:
class PagesController < ApplicationController
has_widgets do |root|
root << widget(:pictures)
end
...
end
I have two views in the Pages controller: "PagesController#Edit" and "PagesController#Show". I also defined two views in the widget controller, one is "PicturesWidget#edit" and the default is "PicturesWidget#display". From the edit and show views, I use something like this to load the widgets:
# In views/pages/show.html.erb:
<%= render_widget :pictures, :display, ... %>
# In views/pages/edit.html.erb:
<%= render_widget :pictures, :edit, ... %>
However, the main issue I am running into is the fact that the user can have multiple widgets per page. In other words, I have to pass in the serialized data
field into each widget, so it can display the content in PicturesWidget#display
or PicturesWidget#edit
views. In the PagesController
I do:
def show
@user = ...
@page = @user.pages.find(params[:page_id])
@widgets = @page.widgets
end
And in views/pages/show.html.erb
I use the following loop:
<% @widgets.each do |widget| %>
<%= render_widget :pictures, :display, :widget => widget %>
<% end %>
This ends up passing-in each individual widget ActiveRecord as an argument to the PicturesWidget
controller. In the widget controller, I added "args" to both display
and edit
methods:
def display(args)
@widget = args[:widget]
@title = @widget.data[:title]
@url = @widget.data[:url]
render
end
This is causing me issues all over the place because when I have to re-render the view or replace it with another, I usually get complaints that "args" is not present, and I have no way to pass it in.
In Apotomo documentation I found that we are supposed to use options instead of args in the newer version of the gem. Options are pulled from the "has_widget" method in the original PagesController
:
has_widgets do |root|
root << widget(:pictures, :data => @data)
end
In this case options[:data]
would return @data
. However, I need to provide data per each widget, not a global @data
var. I wasn't able to find any examples of how others are doing this. Any suggestions? Or should I just scrap the whole thing and write my own Widget Controller? Or downgrade to cells and write my own AJAX handlers?
Sorry for the long write-up. I reckon someone else might run into this issue and hopefully this helps them out.
Thanks, Nick
[Edit] As suggested, I ended up adding unique widgets as so:
@page.widgets.each do |indiv_wid|
root << widget(indiv_wid.kind.to_sym, indiv_wid.id, data: indiv_wid.data)
end
Had to override one of the modules to allow use of apotomo_root in the controller/views:
module Apotomo
module Rails
module ActionViewMethods
delegate :render_widget, :apotomo_root, :url_for_event, :to => :controller
end
end
end
(Added :apotomo_root
above)
Used this in the controller to get a list of all the loaded widgets:
apotomo_root.each do |x|
@widget_ids << x.widget_id unless x.widget_id == :root
end
And then I simply iterated over it in the view:
<% @widget_ids.each do |id| %>
<%= render_widget id %>
<% end %>
you can have separate options per widgets. You should instantiate different widgets for each configuration, anyway. Do so by passing an id the each widget: http://rdoc.info/github/apotonick/apotomo/Apotomo/WidgetShortcuts:widget
class PagesController < ApplicationController
has_widgets do |root|
root << widget(:pictures, 'one', :data => ...)
root << widget(:pictures, 'two', :data => ...)
end
...
end
You can use the widget id in #render_widget
, then.
render_widget 'one'