1

I've made a small gist of it but basically what I'd like to do is

<%= render "this is a #{ I18n.translate(:a_string) }" %>

Saving snippets and/or entire views_templates (like views/mailers/some_model/regards.haml) in a database will allow me to building hierakies of templated views entirely from the web-interface - and saving the designers the round-trip to uploading files to the server, or in less pompous circumstances, having users edit minor screw-ups in templates themselves.

The above example does in no way portray the size of the problem - but point to the heart of it: how to render a template usually sitting in the filesystem, now being a text attribute on a Template model in the database.

lucapette
  • 20,564
  • 6
  • 65
  • 59
walt_die
  • 580
  • 5
  • 20

2 Answers2

0

You could render a partial for a generic template:

<%= render :partial => 'shared/string' %>

Then the partial template does the string rendering:

In shared/_string:

<%= "this is a #{ I18n.translate(:a_string) }" %>

Or you could have the database lookup for stored string done in the render call, and pass it in as a parameter:

<%= render :partial => 'shared/string', :locals => {:a_string => String.find(:string_id)} %>

In shared/_string:

<%= a_string %>

Or if your string contains ERB that needs to be executed try:

<%= ERB.new(a_string).result %>

Rendering a partial like this shouldn't cause the DoubleRender error.

JDutil
  • 3,622
  • 25
  • 32
  • yes - the problem is not render per se; the problem is that if/when I call render I'm caught in the well-known DoubleRender Act – walt_die Feb 23 '12 at 18:13
  • How about the edited answer of rendering a partial that renders your looked up string. – JDutil Feb 23 '12 at 18:21
  • I'm testing it on views/users/mailer/confirmation_instructions.html.erb which has your <%= render partial: 'templates/template', locals: { template: find_template('mail confirmation') } %> # views/templates/_template.haml in turn has: = render text: template but it feeds me the string from the template complete with Erb and everything - infact untouched! But - JDutil - thanx for trying <:) – walt_die Feb 23 '12 at 18:44
  • There is a way to have the erb executed. Need to lookup how to execute ERB and then in your template call the method(s) to execute ERB passing in your variable. I'll try a quick search but this is definitely possible and heading in the right direction I just forget how to execute the erb off the top of my head I have done that before though. – JDutil Feb 23 '12 at 18:59
  • I updated the answer with <%= ERB.new(a_string).result %> which should execute the ERB. See http://stackoverflow.com/questions/980547 – JDutil Feb 23 '12 at 19:02
  • Andrew White with the Rails Team was kind to show me - but did not know of the binding() thing - so took a stab more at it. Alas it turned sour on me again :( the rendering of regular Erb (and HAML) works fine - but I cannot call render, link_to or any other Rails goodness for that matter - which means that all my existing templates are dead in the water (at least pertaining to this scope - ol' time rendering works off cause as usual - but I cannot copy/paste them into my database and start rendering it all from the database. Must be missing something – walt_die Feb 23 '12 at 19:44
  • Are you adding the templates through a web interface? What you could and should do is execute the erb and save the results into the DB. Then when you pull it out you can simply do the initial idea of simply rendering it (with #html_safe of course). This way when your compiling it during the save you should have access to your Rails helper methods, and then you don't need to have the overhead of processing it when you want to render it. – JDutil Feb 23 '12 at 19:57
-1

The answer - at least to my question - is rather convoluted, and requires a great deal of digging into the innards of the Rails stack! I'm merely copy-cat'ing here: go see the complete answer in José Valím's book, Crafting Rails Applications!

With Rails 3.2.1 (possibly even before) templates (as in eg. app/views/posts/show.haml) are 'found' by something called a Resolver, and it is possible to add ones own Resolver - which I did :)

I added a

class ViewTemplate < ActiveRecord::Base
    class Resolver < ActionView::Resolver
      def find_templates(name, prefix, partial, details)
        conditions = {
          :path    => normalize_path(name, prefix),
          :locale  => normalize_array(details[:locale]).first,
          :display_format  => normalize_array(details[:formats]).first,
          :handler => normalize_array(details[:handlers]),
          :partial => partial || false
        }
        ViewTemplate.where(conditions).map do |record|
          initialize_template(record)
        end
      end
    end
end

and then I told my ApplicationController to look at my own path first:

class ApplicationController < ActionController::Base
  append_view_path ViewTemplate::Resolver.new
end

and finally I added a record to my ViewTemplate with

ViewTemplate.create( content: '=render "form"', path: 'posts/edit', display_format: 'html', handler: 'haml' )

and replaced the contents of my views/layouts/application.haml with:

= render 'posts/edit'

and huzzah :)

(well, more or less - there are of cause issues like variables, and scopes - but hey, nothing is perfect)

walt_die
  • 580
  • 5
  • 20
  • Jose Valim covers this in his book, and it's pretty great – Giles Bowkett Aug 21 '12 at 04:06
  • @GilesBowkett - yep! - and if my 'answer' does seem to elicit an odour of original work, I'm to blame (did update the answer with a link to the right honourable Sr José Valím) :) – walt_die Sep 24 '12 at 06:45