Taking advantage of Rails form helpers/partials within Radiant

58 views
Skip to first unread message

Wes Gamble

unread,
Aug 16, 2010, 11:36:31 PM8/16/10
to radia...@googlegroups.com
All,

I have come to a point where I would like to integrate some none-Radiant managed views with Radiant views, and I'm trying to determine the best overall approach. 

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.

Thoughtful responses appreciated.

Many thanks,
Wes

Wes Gamble

unread,
Aug 20, 2010, 12:05:24 AM8/20/10
to radia...@googlegroups.com
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

Wes Gamble

unread,
Aug 20, 2010, 1:59:01 AM8/20/10
to radia...@googlegroups.com
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

Haselwanter Edmund

unread,
Aug 20, 2010, 3:44:29 AM8/20/10
to radia...@googlegroups.com
Hi,

On 20.08.2010, at 07:59, Wes Gamble wrote:

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).

Wes Gamble

unread,
Aug 20, 2010, 5:41:11 AM8/20/10
to radia...@googlegroups.com
Edmund,

I did see this, but I don't think it exactly addresses my issue.  I want to render a page where half of my content is provided by a Radiant user, and the other half is provided by me (the developer). 

share-layouts basically allows us to plug in the holes in the Radiant layout from a Rails controller/view pair, but then all of the content must come from the Rails app., correct?

In my current scheme, the minimal amount of content that has to be in the Rails filesystem is there, and everything else is in Radiant, where I want it. 

Can you think of a way that I could successfully use share-layouts and still render a Radiant managed part in a Rails generated page?

Many thanks,
Wes

Haselwanter Edmund

unread,
Aug 20, 2010, 6:27:23 AM8/20/10
to radia...@googlegroups.com

> Edmund,
>
> I did see this, but I don't think it exactly addresses my issue. I want to render a page where half of my content is provided by a Radiant user, and the other half is provided by me (the developer).

Then I don't understand your use case. Either use radius tags to render your data, or use share layouts to populate your data.

> share-layouts basically allows us to plug in the holes in the Radiant layout from a Rails controller/view pair, but then all of the content must come from the Rails app., correct?

hm. radiant is the rails app.

> In my current scheme, the minimal amount of content that has to be in the Rails filesystem is there, and everything else is in Radiant, where I want it.
>
> Can you think of a way that I could successfully use share-layouts and still render a Radiant managed part in a Rails generated page?

http://github.com/screenconcept/radiant-page-part-handling-extension

Mark Reginald James

unread,
Aug 20, 2010, 7:54:51 AM8/20/10
to Radiant CMS
To render a partial in a tag I've been doing

tag('show_user_status') do |tag|
response.template.render :partial => 'users/status', :locals =>
{:user => User.find(params[:id])}
end

You can also add scripts and stylesheets to the page head, and use
other view helpers

tag('show_user_status') do |tag|
view = response.template
controller = view.controller
controller.include_javascript 'users'
controller.include_stylesheet 'users'
view.content_tag :div, :id => 'user-status-div' do
view.collection_select(:user, :id, User.all, :id, :name, :prompt
=> true) +
response.template.render(:partial => 'users/status', :locals =>
{:user => User.find(params[:id])})
end
end

or one big String

tag('show_user_status') do |tag|
%{
<div id="user-status-div">
#{response.template.render :partial => 'users/status', :locals
=> {:user => User.find(params[:id])}}
</div>
}
end


I've found it best to use as many custom tags and as few custom Rails
actions as possible, so as to maximize the amount of content able to
be controlled via the web interface.

Mark Reginald James

unread,
Aug 20, 2010, 8:36:37 AM8/20/10
to Radiant CMS


Mark Reginald James wrote:
> I've found it best to use as many custom tags and as few custom Rails
> actions as possible, so as to maximize the amount of content able to
> be controlled via the web interface.

...page tree. The share-layouts extension allows fixed-parts of custom-
action pages to be user-editable, but you get a proliferation of
layouts, rather than a complete hierarchy of pages.

Wes Gamble

unread,
Aug 20, 2010, 12:27:12 PM8/20/10
to radia...@googlegroups.com
On 8/20/10 5:27 AM, Haselwanter Edmund wrote

>> Edmund,
>>
>> I did see this, but I don't think it exactly addresses my issue. I want to render a page where half of my content is provided by a Radiant user, and the other half is provided by me (the developer).
> Then I don't understand your use case. Either use radius tags to render your data, or use share layouts to populate your data.

>> share-layouts basically allows us to plug in the holes in the Radiant layout from a Rails controller/view pair, but then all of the content must come from the Rails app., correct?
> hm. radiant is the rails app.

I misspoke here (it was late), what I meant was to distinguish between
the two render paths available to me in the Rails app. - either
SiteController - driven [Radiant - managed rendering] or standard Rails
rendering. As far as I can tell, these two render paths are effectively
mutually exclusively across the entire page. Either my entire page is
rendered by Radius tags, or my entire page is rendered by share layouts.

Neither of these is sufficient if I need to render both content
contained inside of Radiant and content that comes from a standard Rails
request _in the same page_.

Specifically, in my applicaiton - in one page, I have a piece of content
that is rendered at the top of the page, and then a form that needs to
be rendered at the bottom. Truth be told, I could use the forms
extension to render the form, but having to hand-code all of the field
attributes was distasteful to me, when I could use a standard Rails form
builder based view, do it in Haml, and have the form view be more
readable, etc. What I probably _should_ do is change the forms
extension to be able to take advantage of the form builder stuff in
Rails, so that writing out a Radius form isn't as tedious as it is now.

Having said all of that, I'm pretty happy with what I have so far as it
gives me what I think is more flexibility.

I looked at the page-part extension as well, but it didn't seem to
address my issue, since one of my parts would be one of these forms.

I will keep thinking about it. It's certainly possible that there is a
more elegant solution.

Many thanks,
W

Wes Gamble

unread,
Aug 20, 2010, 1:05:28 PM8/20/10
to radia...@googlegroups.com
I went down this path, but ultimately, going through all of the effort
to "manually" render a template and then wrapping it up in a Radius tag
didn't seem worth it to me.

The Radiant user does get to control the :locals data that is passed in
to the partial, but the partial still lives outside of Radiant, so the
raw content is still outside of Radiant.

What I didn't realize is that it looks like you have access to the HTTP
response in the custom tag - is that correct? That's quite helpful.

I may try to do something like this in the future if it makes sense.
Thanks for the info.

Wes


Reply all
Reply to author
Forward
0 new messages