On 8/19/10 11:05 PM, Wes Gamble wrote:
On 8/16/10 10:36 PM, Wes Gamble wrote:
All,
I have some custom models which need to be represented in Radiant
views, and I would like to be able to take advantage of standard
Rails partials, Rails form helpers, (e.g. all the good things about
ActionView).
I have a custom extension which holds all of my model information. I
have, in addition, created a Radius tag that is very close to
rendering a standard Rails partial using standard form helpers. I
can't really see the point in using the forms extension when the
field helper tags in it provide less functionality than standard
Rails helpers (and there is no support for textarea <input> elements).
Generally speaking, it seems that there are 3 options:
1) Do not use Rails partials at all, enhance the existing forms
extension to provide more ActionView helper-like functionality.
Basically, stay within the limits of Radiant.
2) Continue down the path I'm on, which is basically wrapping a Rails
partial with a Radiant tag (similar to this post from the Radiant
list: http://www.ruby-forum.com/topic/133878)
3) Figure out a way to hook into the Site controller and merge
content generated via both standard Rails mechanisms and Radiant (I
know how to hack around double render issues, etc.). I'm thinking
that the SiteController could basically become a mini-dispatcher when
necessary to run standard Rails actions, and ultimately render
standard Rails views/helpers, which can then be inserted into the
HTTP response.
At the risk of being chastised for responding to my own post, I
thought I would update everyone on my progress.
Firstly, I forgot that <textarea> is it's own tag, so my assertion
that the forms extension was incomplete was of course, incorrect.
As for the three approaches, here's what I discovered - I ended up not
doing any of them.
1) Since custom Radius tags are executed only in the context of the
Radiant rendering process (which is bound to SiteController), to add
all the coolness I wanted would have been prohibitive.
2) I investigated creating a custom tag and learned a great deal, and
started looking into how I would initiate a standard Rails request
from within a SiteController action. But I ended up not really
needing a custom tag after all.
3) I did look into how to hook into the Site controller, thinking that
I could basically put a custom tag in a page part which would
effectively hold the URL for the action that I needed to run. Then I
would just initiate my standard Rails action during the standard
SiteController action processing of that page part. However, I ended
up trying to construct a valid Rails HTTP request object on the fly
(which I had some limited success at), which started to suck up too
much time. Truth be told, I would much rather that I be able to do it
this way so that I only incur a minimum of overhead (see CONS below).
What I really wanted to do was to execute the action in question as a
normal HTTP request and take the results and merge them with the
Radiant generated page. That way, all of the standard Rails magic
would just work.
So here's what I ended up doing:
* I create a Javascript function (stored in Radiant) to generate my
Rails view (this is jQuery):
function generate_objection_form(obj_type_id) {
$.ajax({async: false,
url: '/admin/objection_instances/new',
data: {objection_type_id: obj_type_id},
complete: function(response)
{$('script').last().before(response.responseText)}})
}
Note that this Ajax call executes _synchronously_ so that the content
is rendered before the page returns.
* In each page that I need this form to appear, I add the following
<script> tag:
<script type="text/javascript">generate_objection_form(1)</script>
When the <script> tag is encountered, the Ajax call gets fired,
synchronously, and the content is inserted before the script tag that
made the call.
PROS:
* This is a standard Rails request, so no additional magic needed
* I can insert content at any point in the page using this scheme (I
need to modify the content insertion function to key off of an
attribute in the <script> tag - that way I don't have to depend on the
positioning of the tag like I'm doing now ($('script').last()).
CONS:
* This approach requires at least one additional request/response for
any custom content, granted it is lighter weight, most likely.
* My content templates are now split between Radiant (as
pages/parts/snippets) and the Rails app (as standard view templates).
It would be nice to be able to put the content into a page part and
keep it all in Radiant.
Hope this is of use to someone.
Thanks,
Wes
A refinement of sorts:
* generic target URL and data
* use of Ruby route helpers to generate URLs (I hate having to hard
code URLs in Javascript when I have all these Ruby helpers to generate them)
* truly location-independent content updating based on tag attributes
instead of DOM position
Javascript function:
function generate_custom_content(url, data) {
$.ajax({async: false,
url: url,
data: data,
complete: function(response)
{$('script#replace').replaceWith(response.responseText)}})
}
Snippet named "rails_content" to call Javascript function (haml filter):
%script{:id => "replace", :type => "text/javascript"}
generate_custom_content(<r:yield/>)
Page code to render snippet (which in turns invokes Javascript and pulls
in the content):
<r:snippet
name="rails_content">'<r:ruby>new_admin_objection_instance_path</r:ruby>',
{objection_type_id: 1}</r:snippet>
Wes