render_to_string in lib class not working - ruby-on-rails

I'm trying to use delayed_job to update a remote database via xml
In my lib folder I put a file with a class that should do a render_to_text with template.xml.builder, but I get:
undefined method `render_to_string' for #<SyncJob:0x7faf4e6c0480>...
What am I doing wrong?

ac = ActionController::Base.new()
ac.render_to_string(:partial => '/path/to/your/template', :locals => {:varable => somevarable})

I had problems with a undefined helper method then I used ApplicationController
ApplicationController.new.render_to_string

render_to_string is defined in ActionController::Base. Since the class/module is defined outside the scope of the Rails controllers the function is not available.
You are going to have to manually render the file. I don't know what you are using for your templates (ERB, Haml, etc.). But you are going to have load the template and parse it yourself.
So if ERB, something like this:
require 'erb'
x = 42
template = ERB.new <<-EOF
The value of x is: <%= x %>
EOF
puts template.result(binding)
You will have to open the template file and send the contents to ERB.new, but that an exercise left for you. Here are the docs for ERB.
That's the general idea.

Rails 5
render_to_string and others are now available as class methods on the controller. So you may do the following with whatever controller you prefer: ApplicationController.render_to_string
I specifically needed to assign a dynamic instance variable for the templates based on an object's class so my example looked like:
ApplicationController.render_to_string(
assigns: { :"#{lowercase_class}" => document_object },
inline: '' # or whatever templates you want to use
)
Great blog post by the developer who made the rails PR: https://evilmartians.com/chronicles/new-feature-in-rails-5-render-views-outside-of-actions

You could turn your template.xml.builder into a partial (_template.xml.builder) and then render it by instantiating an ActionView::Base and calling render
av = ActionView::Base.new(Rails::Configuration.new.view_path)
av.extend ApplicationController.master_helper_module
xml = av.render :partial => 'something/template'
I haven't tried it with xml yet, but it works well with html partials.

Related

How to replace erb with liquid?

I'd like to use liquid in my Rails app. I've installed the gem. In order to use in all templates, I've created a library (lib/liquid_view.rb:):
class LiquidView
def self.call(template)
"LiquidView.new(self).render(#{template.source.inspect}, local_assigns)"
end
def initialize(view)
#view = view
end
def render(template, local_assigns = {})
#view.controller.headers["Content-Type"] ||= 'text/html; charset=utf-8'
assigns = #view.assigns
if #view.content_for?(:layout)
assigns["content_for_layout"] = #view.content_for(:layout)
end
assigns.merge!(local_assigns.stringify_keys)
controller = #view.controller
filters = if controller.respond_to?(:liquid_filters, true)
controller.send(:liquid_filters)
elsif controller.respond_to?(:master_helper_module)
[controller.master_helper_module]
else
[controller._helpers]
end
liquid = Liquid::Template.parse(template)
liquid.render(assigns, :filters => filters, :registers => {:action_view => #view, :controller => #view.controller})
end
def compilable?
false
end
end
And added the following initialiser (config/initializers/liquid_template_handler.rb:):
require 'liquid_view'
ActionView::Template.register_template_handler :liquid, LiquidView
PS: I've followed these instructions.
Now, if rename a template file with liquid my_template.html.liquid the <%= stylesheet_link_tag 'mycss' %> stopped working, but more importantly the {{user.first_name}} variable did not print. In my controller I have #user = current_user
What am I missing?
My intention is to completely override erb with liquid in some templates, so ideally it should work like erb (in a sense that I can pass variables from the controller and simply render it in the template without using Liquid::Template.parse(#page.template) which by the way, I don't understand how it works on a file-based template.
PS: I'm also using [this] gem (https://github.com/yoolk/themes_on_rails) for separate templates. I'm not sure it does any impact on it.
PPS: I've seen this but doesn't apply as its a older version of Rails and I'm not using prepend.
PPPS: I'm using Ruby 2.2.2 and Rails 4.2
I hope this not the problem you are thinking it is . You can check the way as it was said here Github Description
Did you create a Drop to access #user?
https://github.com/Shopify/liquid/wiki/Introduction-to-Drops
Liquid is a safe template system, so we can interpret on the backend templates that are created by the user. To access anything non trivial (number, string, hashes or arrays) you need a Drop, which is a controlled interface to define what the templates can access.
This is by design and for security reasons.

How does one use instance methods in a static method? I'm trying to async'ly create a document

In my controller, i have a method defined as:
def self.store_pdf(id)
...
end
in that method, I need to call render_to_string to render the correct file / layout:
render_to_string(
:action => "../view/current_version/show.pdf.erb",
:layout => false)
but because render_to_string is both an instance method and protected, I need to do the following:
me = self.new # self is the cortroller
me.send(:render_to_string,
:action => "../view/current_version/show.pdf.erb",
:layout => false)
but then there are dependencies such as the response object that render_to_string needs to work, as shown here: http://apidock.com/rails/ActionController/Base/render_to_string
So, I began adding them
me.send(:response=, ActionController::Response.new)
But, more and more of the global instance variables need to be defined, and I decided it was too much work just to try to get one static method to work.
The method needs to be static, so that delayed_job can run the method in the background at a later time.
Anyone have an idea as to how to pull this off?
You can read erb via ERB if you are not using any rails helper,If you are using any rails helper then include Rails helper.
you can refer using here or
require 'erb'
class PdfRender
#include ActionView::Helpers::OutputSafetyHelper
#include helper if any is present any
def self.render_pdf(id)
#set any instance variable if you are using in pdf
content = File.read('path/of/erb/template')
template = ERB.new(content)
# template content will give you text now you can render or generate pdf
template_content = template.result(binding)
end
end
Note:
replace h() with CGI.escapeHTML()

Render ERB Template in RABL Template

I have a scenario where I'd like to pass back a long message with my JSON. Instead of writing it out with string concatenation I'd rather put together an erb template that I can render into my JSON. Below is the code I'm currently trying:
object #invitation
node(:phone_message) do |invitation|
begin
old_formats = formats
self.formats = [:text] # hack so partials resolve with html not json format
view_renderer.render( self, {:template => "invitation_mailer/rsvp_sms", :object => #invitation})
ensure
self.formats = old_formats
end
end
Everything works as expected the first time this code is run, however, I run into problems the second time I run it because it says there is a missing instance variable (which I assume was generated and cached during the first run).
undefined method
_app_views_invitation_mailer_rsvp_sms_text_erb___2510743827238765954_2192068340
for # (ActionView::Template::Error)
Is there a better way to render erb templates into rabl?
You could try using ERB as standalone, and not going through the view renderer, like so:
object #invitation
node(:phone_message) do |invitation|
begin
template = ERB.new(File.read("path/to/template.erb"))
template.result(binding)
end
end
binding is a method on Object (through the Kernel module) and it returns the binding which holds the current context, which also includes instance variables (#invitation in this case)
Update:
Don't really know if this will help you get any further (and I also realised it's been more than a year since you posted this), but here's another way to render ERB templates in a standalone fashion:
view = ActionView::Base.new(ActionController::Base.view_paths, {})
class << view
include ApplicationHelper
include Rails.application.routes.url_helpers
end
Rails.application.routes.default_url_options = ActionMailer::Base.default_url_options
view.render(:file => "path/to/template.html.erb", :locals => {:local_var => 'content'})
When I have time I should actually try this with Rabl.

Using rails methods with Haml::Engine

I want to have a rake task that reads a HAML file and creates a static html file out of it. The reason for this is that I want to dynamically localize my error pages in a manner described here http://devcorner.mynewsdesk.com/2010/01/13/rails-i18n-and-404500-error-pages/
Here is the method for writing the error pages.
def write_error_page(status, locale = nil)
dest_filename = [status.to_s, locale, "html"].compact.join(".")
File.open(File.join(Rails.root, "public", dest_filename), "w") do |file|
path = File.join(Rails.root, "app", "views", "errors", "#{status}.haml")
file.print Haml::Engine.new(File.read(path)).render
end
end
The problem is that Haml::Engine does not have rails methods available. So when a try to read the haml file, I get an error for every rails method in the file (I want to use methods
like image_tag, form_for and obviously I18n.translate).
I noticed a similar issue that had been solved here: Rails HAML engine rendering
However, when I try the solution mentioned in the link above, I get the following error: "undefined local variable or method `config' for #".
How could I get the rails methods to work in the Haml::Engine so that I could read the HAML file? I also tried switching to ERB, but noticed that it leads to the same problem, which somebody else has at least partially resolved here render erb from database into view problem please help! But this solution didn't help me either.
I'm also open to other solutions than using Haml::Engine. I looked into capture_haml helper but don't see how that would help me either.
You need to make :environment a dependency of your rake task:
task :some_task => :environment do
# stuff here
end
This will load Rails. It sounds like it's not been loaded.
I just now realized that I don't need Haml::Engine in this situation, because I'm in a rails environment so I can just call render. Silly me.
However, it's not completely trivial to call render from a rake task, because we are not in a controller or a view (and so rails purists even say that you should never do so, I think, but in this case it seems like the easiest way), so I post the code I used here (I used the approach mentioned here: http://wholemeal.co.nz/blog/2011/04/05/rendering-from-a-model-in-rails-3/).
def write_error_page(status, locale = nil)
dest_filename = [status.to_s, locale, "html"].compact.join(".")
File.open(File.join(Rails.root, "public", dest_filename), "w") do |file|
path = File.join("app", "views", "errors", "#{status}.haml")
file.print ActionView::Base.new(Rails.configuration.paths.app.views.first).render(:file => path)
end
end
I had some problems with this approach too. For instance, form_for still didn't work properly (I want to have a feedback form on the error page) so I simply created the form with plain HTML (which you can luckily inject straight into .haml files). But the one thing from rails I needed to get to work in the .haml template - method I18n.translate - works like charm.
I did this solution based on yours, once yours wasn't working for me, because of the views path, and because i needed to include some functions from my application helper. I think you can resolve the form_for problem including this: ActionView::Base.send :include, ActionView::Helpers::FormHelper
I change the format to html, because it was what i needed...
def to_html
ActionView::Base.send :include, ActionView::Helpers::ApplicationHelper
File.open(File.join(Rails.root, "public", 'test.html'), "w") do |file|
file.print ActionView::Base.new(Rails.configuration.paths["app/views"].first).render(
:partial => 'partial_folder/partial',
:format => :html,
:locals => { :model => self}
)
end
end

How to render a Partial from a Model in Rails 2.3.5

I have a Rails 2.3.5 application and Im trying to render several Partials from within a Model (i know, i know -- im not supposed to). The reason im doing this is im integrating a Comet server (APE) into my Rails app and need to push updates out based on the Model's events (ex. after_create).
I have tried doing this:
ActionView::Base.new(Rails::Configuration.new.view_path).render(:partial => "pages/show", :locals => {:page => self})
Which allows me to render simple partials that don't user helpers, however if I try to user a link_to in my partial, i receive an error stating:
undefined method `url_for' for nil:NilClass
I've made sure that the object being passed into the "project_path(project)" is not nil. I've also tried including:
include ActionView::Helpers::UrlHelper
include ActionController::UrlWriter
in the Module that contains the method that makes the above "render" call.
Does anyone know how to work around this?
Thanks
We use the render_anywhere gem and have been happy with it.
From the README:
require 'render_anywhere'
class AnyClass
include RenderAnwhere
def build_html
html = render :template => 'normal/template/reference',
:layout => 'application'
html
end
end
Including these two modules should be enough. Maybe you forgot to set default_url_options[:host]? Without it you can use _path helpers, but not _url ones.
Include these modules and check out if it works in irb, maybe it will lead you to right solution.

Resources