In an extension I'm working on, I'd like to define some medium to large blocks of dynamic html to be inserted via a single radius tag. Because this html isn't just a line or two and is tied to models and their data, I'd love to be able to create a true rails partial and tell the snippet to behave as a pseudo-controller and render the view in place of the radius tag. I'm trying to keep a separation of concerns here and keep my code clean (and make use of all the html/erb sugar already built into rails). I don't suppose that there's any way to have a tag call 'render :partial => ...' much less get around the rails double-render when the SiteController tries to render. Clever thoughts anyone? -Chris
on 2007-12-04 07:48
on 2008-01-17 13:18
Chris Parrish wrote: > In an extension I'm working on, I'd like to define some medium to large > blocks of dynamic html to be inserted via a single radius tag. Because > this html isn't just a line or two and is tied to models and their data, > I'd love to be able to create a true rails partial and tell the snippet > to behave as a pseudo-controller and render the view in place of the > radius tag. > > I'm trying to keep a separation of concerns here and keep my code clean > (and make use of all the html/erb sugar already built into rails). > > I don't suppose that there's any way to have a tag call 'render :partial > => ...' much less get around the rails double-render when the > SiteController tries to render. Clever thoughts anyone? > > -Chris Hi Chris, I've a simple example how you can do this: Model: require 'radius' class Content < ActiveRecord::Base def body context = Radius::Context.new do |c| c.define_tag 'render' do |tag| content = "<!--partial-->[render]=" + tag.attr['partial'] + "<!--partial-->" end end parser = Radius::Parser.new(context, :tag_prefix => 'r') return parser.parse('<p>hello <r:render partial="partials/google_adsense" /></p>') end end View: <div class="body"> <% @content.body.split("<!--partial-->").each do |body| %> <% if body.include?("[render]=") %> <%= render :partial=>body.split("[render]=")[1] %> <% else %> <%= markdown(body) %> <% end %> <% end %> </div> Maybe i could help you
on 2008-01-17 14:43
Hi Chris, Now that Alexandro brings this up again, I have managed to add the ability to truly render a partial inside a tag, model or anywhere else you'd need to do it. It is, however, part of an extension with loads of other stuff in it, and it requires some ugly hacks. Amongst other things, Radiant has to be hacked to set the active controller, request and response on tags.globals, so they are available to initialize an ActiveView::Base instance to render a partial inside the tag. If you are interested, I could provide the required code for in a pastie, but you might want to stick with Alexandros solution which seems less hacky, albeit not bullet proof. (How do you for instance pass data to the partial with this approach?) Cheers, Casper Fabricius
on 2008-01-17 17:20
@Alexlandros - when I get some free time in the next couple of days, I'm
going to take a look at your solution. It's not exactly the direction I
need (I have tags like <r:my_tag name="some_name"> which spits out a big
block of html with data from my a model. But I'm not trying to let the
user render a partial by name. But the foundation is still the same so
I'd like to understand it better - maybe we'll talk off the list.
@Casper - I'm not into hacks much but I would be interested in any
suggestions/improvements. Also, I didn't feel like I needed another
controller since it would only be finding and creating a model to pass
to the view (pretty simple). But that doesn't mean being able to trigger
another controller wouldn't be useful (I've often wanted something sort
of like the now deprecated Rails 'components.' They were bad practice
there but in this environment where there's a SiteController overseeing
all, being able to chain a 2nd controller into the mix would be nice).
If you'd be willing to email me a pastie directly I'd appreciate it.
Thanks both of you.
And, for the record, I came up with a solution that I was ok with (and
light on hacks). Here's what I did:
[In the Model]
tag "my_tag" do |tag|
@my_tag_data = MyModel.find_by_name(tag.attr['name'])
parse_template 'path_for/_my_template'
end
end
private
def parse_template(filename)
require 'erb'
template = ''
File.open("#{MyExtensionNameExtension.root}/app/views/" + filename +
'.html.erb', 'r') { |f|
template = f.read
}
ERB.new(template).result(binding)
end
[In
/vendor/extensions/my_extension_name/app/views/path_for/_my_template.html.erb]
<h1><%= @my_tag_data.name -%></h1>
<p>Value from my instance variable: <%= @my_tag_data.value -%></p>
So you can see that I chose to follow the Rails 2.0 template naming
rules of '*.html.erb' (since John's been making progress towards a 2.0
capable Radiant- yay!). I used ERB with binding so I was able to pass
instance variables to the template (something I needed).
This obviously isn't full-on rails parsing so it doesn't auto-mixin
helpers or anything fancy like that (I suppose I could require
ActiveView::Base or some such thing) but I didn't need that much
capability.
-Chris
on 2008-01-18 09:55
Chris, what can I say, your solution is better and cleaner than mine. My solution lets the partial render in the context of the SiteController, with the exact same possibilites as when rendered the standard way, but I think I'll switch to yours anyway and get rid of some my ugly hacks and overrides. Thanks for providing your solution - I'd provide mine, if I thought it would actually be a help to anyone, but I don't ;) /Casper
on 2008-11-21 20:30
Chris Parrish's solution to rendering partials within a Radius tag works great. It's been almost a year since he posted it though, and I was wondering if this functionality should be done a different way now -- i.e. does Radiant has a built-in way to handle this now? Thanks, - Dave Chris Parrish wrote: > > [In the Model] > > tag "my_tag" do |tag| > @my_tag_data = MyModel.find_by_name(tag.attr['name']) > parse_template 'path_for/_my_template' > end > end > > private > > def parse_template(filename) > require 'erb' > template = '' > File.open("#{MyExtensionNameExtension.root}/app/views/" + filename + > '.html.erb', 'r') { |f| > template = f.read > } > ERB.new(template).result(binding) > end > > > [In > /vendor/extensions/my_extension_name/app/views/path_for/_my_template.html.erb] > > <h1><%= @my_tag_data.name -%></h1> > <p>Value from my instance variable: <%= @my_tag_data.value -%></p> > > This obviously isn't full-on rails parsing so it doesn't auto-mixin > helpers or anything fancy like that (I suppose I could require > ActiveView::Base or some such thing) but I didn't need that much > capability. > > -Chris
on 2008-11-21 22:46
David, I still use that code in my extensions today (though I'd be interested to hear if anyone out there has come up with something better). Now that Haml is built into Radiant, it would also be safe to convert to using that for your templates (it might be even easier to do the binding bit but I haven't tried yet). -Chris
on 2008-11-22 00:05
That pattern seems like a sufficiently good paradigm that some sort of
convention should be created to do this. Perhaps
tag "my_tag" do |tag|
@my_tag_data = MyModel.find_by_name(tag.attr['name'])
tag.render
end
end
>
would automatically use view/tags/my_tag.haml.html or something similar.
on 2008-11-24 18:13
Chris -- any idea why I can't use the h() method in my partials? NoMethodError in SiteController#show_page undefined method `h' for #<MyControllerName:0x3336ca8> - Dave Chris Parrish wrote: > David, I still use that code in my extensions today (though I'd be > interested to hear if anyone out there has come up with something > better).
on 2009-03-02 13:51
Chris Parrish wrote: > David, I still use that code in my extensions today (though I'd be > interested to hear if anyone out there has come up with something > better). > > Now that Haml is built into Radiant, it would also be safe to convert to > using that for your templates (it might be even easier to do the binding > bit but I haven't tried yet). Here's a HAML version that works, up to a point. It's not really much use, though: out of context like this you can render haml and interpolate variables but that's about it. You can't render another partial, for example, or call any helper methods. Perhaps someone more up on scopes and evaluation can make it work? def parse_template(filename, locals = {}) require 'haml/engine' haml_engine = Haml::Engine.new(File.read("#{SomeExtension.root}/app/views/" + filename + '.html.haml')) haml_engine.to_html(Object.new, locals) end best, will
on 2009-05-25 13:31
William Ross wrote: > Here's a HAML version that works, up to a point. It's not really much > use, though: out of context like this you can render haml and > interpolate variables but that's about it. You can't render another > partial, for example, or call any helper methods. Perhaps someone more > up on scopes and evaluation can make it work? There is another possibility, that allows using @variables and render :partials: params = {:id => 15} env = { 'REQUEST_METHOD' => 'GET', 'REQUEST_URI' => '/search/details', 'action_controller.request.request_parameters' => params } r = SearchController.new r.process(ActionController::Request.new(env), ActionController::Response.new, :details).body and then implement search_controller as usual, but it looks like you need to call render :action => 'details' explicitly.
on 2010-08-17 00:45
Is anyone aware of any progress that has been made in this area? I find myself needing to do the same thing. Thanks, Wes
on 2010-10-05 19:11
I ended up using Cells (http://github.com/apotonick/cells) to handle this. In my xxx_extension.rb, file I needed to do the following in order to allow the PageController to handle cells: #Modify view paths for ::Cell::Base to include local cell view directories ::Cell::Base.view_paths += [CELL_PATH, "#{CELL_PATH}/layouts"] #Add CELL_PATH to Rails $LOAD_PATH $LOAD_PATH.unshift CELL_PATH #Require each Cell class CELL_FILES.each {|f| require f} and I added a custom "cell" tag to handle rendering of cells: desc %{ For use with projects that use the Cells gem (http://github.com/apotonick/cells) Renders the cell specified in the @name@ attribute _outside_ of the context of a page. The cell name and view are specified in the appropriate attributes, and local data required for rendering the view may be provided via additional tags, which will be passed through to cell in its @opts hash. *Usage:* <pre><code><r:cell name="cell_name" view="view_name" data_param_1="x" data_param_2="y"/></code></pre> } tag "cell" do |tag| if tag.attr['name'] && tag.attr['view'] name, view = tag.attr.delete('name'), tag.attr.delete('view') tag.locals.page.response.template.controller.render_cell(name, view, tag.attr) else raise TagError.new("`cell' tag must contain `name' and `view' attributes") end end
Please log in before posting. Registration is free and takes only a minute.
Existing account
(Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
Log in with Google account | Log in with Yahoo account
No account? Register here.