How to set #virtual_path true in refresh() in ActionView::Template? - ruby-on-rails

We use render inline in our rails 3.2 app:
<%= render inline: #erb_code, locals: {f: f} %>
Here #erb_code returns a string of ERB code for rendering. The problem with this inline is that the #virtual_path is set to false in rendering which causes error in spec in refresh(view) of ActionView::Template. Here is the error:
ActionView::Template::Error:
A template needs to have a virtual path in order to be refreshed
Here is the line in definition of refresh which causes error:
raise "A template needs to have a virtual path in order to be refreshed" unless #virtual_path
The full definition of the refresh(view) is available at http://api.rubyonrails.org/classes/ActionView/Template.html.
How to set #virtual_path true in rspec to avoid the spec error? But the execution of the code seems having no error. Tried assign true to #virtual_path in spec and it did not work.

You can try to stub this refresh call in the beinning of your spec
ActionView::Template.any_instance.stub(:refresh)

Related

How to stub a flash in a RSpec spec?

In my view, I have a hidden_field_tag whose value is a flash set in the controller. In other words, the flow is as follows:
Controller:
def home
flash[:id] = 123
end
View:
<% form_tag(new_invitee_path) %>
<%= hidden_field_tag :referer, flash[:id] %>
<% end %>
Params submitted to new_invitee_path:
{ "referer" => "123" }
I can confirm that in manual testing this works appropriately, but I can't figure out how to stub appropriately.
In my test I have:
before do
#set flash
visit '/home'
fill_in "rest_of_form"
click_button "submit_form
end
Where below are the things I've tried to do for set flash and the error messages I get:
flash[:id] = 123
# OR
flash.now[:id] = 123
# both render error: undefined local variable or method `flash' for #<RSpec::Core::ExampleGroup::Nested_1::Nested_1:0x007fc1040f7d60>
# Have also tried a tactic found online to set flash for response object like this:
visit '/home'
response.flash[:id] = 123
# OR
response.flash.now[:id] = 123
# both render error: undefined local variable or method `response' for #<RSpec::Core::ExampleGroup::Nested_1::Nested_1:0x007fe118a38490>
#Have read online that it's a problem with the flash being sweeped, so I tried to stub out the sweep, but am unclear how to set the anonymous controller or whatever correctly
controller.instance_eval{flash.stub!(:sweep)}
flash[:id] = 123
# OR
flash.now[:id] = 123
# renders error: undefined local variable or method `flash' for nil:NilClass
Your spec is a feature spec, so the spec environment has no access to things like the flash. Don't try to work with the flash directly. Instead, ideally, test that the user's view of the app looks and/or behaves the way that it should if the flash value is set the way that it should be. I wouldn't just test that the hidden field is present in the form; I'd test that it has the effect that it should after the form is submitted. That's what feature specs are all about: testing that the application works as a whole from the user point of view.
If the flash value isn't ever used in the UI, just logged or stored in the database, it would be OK to test that the log line or model object has the value that's stored in the flash. (The user here is the admin who would look at the log or whatever later.) But if the flash does affect the UI, testing that is preferable.
This seems to work pretty well for me:
YourController.any_instance.stub(:flash) { {some: "thing" }}

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.

How to render partial in HAML that only contains a conditional block

I'm new to Ruby and HAML and attempting to render the following partial inside of main HAML file. The partial consists of only an if conditional. I would like the if conditional to return the output of the partial's HAML code to the main template if the condition is met, and to render nothing if it isn't. The following code works if the array "attachments.each_file" is empty (it renders nothing as I would like), but if it isn't empty it throws an error when it tries to proceed into the if conditional's code. Here are the relevant code snippets:
Error Message:
LocalJumpError in Questions#show
Showing /questions/_attachments.html.haml where line #1 raised:
no block given (yield)
Main HAML template code:
= render "slashbias/questions/attachments", :attachments => #question.attachments, :editing => false
Partial HAML code:
- if !attachments.each_file.empty?
%dl#attachments_list
%dt.header Attached files:
%dd
-attachments.each_file do |key, file|
= link_to file.name, question_attachment_path(question.group, question, file, key)
-if editing
= link_to t("scaffold.destroy"), remove_attachment_question_path(question, :attach_id => key), :class => "remove_attachment_link"
I believe attachments.each_file on line 1 is expecting a block. It doesn't throw an error in the case of having 0 files, because it never attempts to yield anything. But in the case that there are files, each_file is trying to yield the files to a block and raising the error you're seeing because there is no block to yield to.
Is there another way for you to test if there are any files? Something like !attachments.files.empty? or attachments.files.count > 0?

ActionView::TemplateError (Missing template) In ruby on rails

I am running a RoR application (rails 2.3.8, ruby 1.8.7), the application runs fine on my local machine. but on production the logs show the following error:
ActionView::TemplateError (Missing template folder/_file_name.erb in view path app/views) on line #19 of app/views/layouts/main.rhtml:
19: <%= render :partial => "folder/file_name" -%>
the file name exists as folder/_file_name.html.erb, I tried to reproduce the problem on the production environment but didnt have any luck, for some reason rails application asks for folder/_file_name.erb at some times while other times it searches for the right file folder/_file_name.html.erb.
Could someone explain to me what is going on?
The same also occurs for .rhtml files, rails application requests .erb at times while others get the right .rhtml file
update:
<%= render :partial => "shared/meta_tags" -%>
<%= render :partial => "shared/common_resources" -%>
<%= render :partial => 'shared/ads/oas' -%>
Any pointers on this issue will be helpful,
thanks in advance
Whats the format of the request?, for the first template (folder/_file_name.html.erb) it will only be correct if the request format is html, but not if it is ajax or any other custom type you have in your app. One quick soluction would be to rename it to folder/_file_name.erb if you want to use the same partial for all the formats
Is there a controller action with the same name as that file?
If you have a foo controller with a bar action and no response defined in your action, Rails will try and render views/foo/bar.html.erb.
If that's not what you want, you need to define a response in your controller and tell Rails to render the appropriate partial, like so:
respond_to do |format|
format.html do
render :partial => "/foo/bar"
end
end
In the latter case, Rails will render "views/foo/_bar.html.erb"
In some cases You can't prevent this error as there are load reasons like missing cache, unknown request format and etc
You can try to restrict the number of predefined formats like:
get '/about-us' => 'controller#about', :format => /(?:|html|json)/
However, I added the following method in my application_controller.rb file so that such errors will render a 404 page rather failing with a error message on screen
rescue_from ActionView::MissingTemplate, :with => :rescue_not_found
protected
def rescue_not_found
Rails.logger.warn "Redirect to 404, Error: ActionView::MissingTemplate"
redirect_to '/404' #or your 404 page
end
you can wrap this code in a if statement, something like this if Rails.env.production? given that the env is setup so your dev environment wont be affected

Resources