Is it possible to convert a string into a partial? - ruby-on-rails

I have a string that stored in my database that is used as a custom layout.
I would like to parse their custom layout inside of my app layout, by using :
render_to_string(partial: custom_template, layout: "pdf_template", locals: locals)
Where custom_template is the string from the DB. However, when I try to do this I get :
NoMethodError: undefined method `to_sym' for nil:NilClass
Is it possible to do what I'm doing? If so, what can I do to complete this?
I've noted that I can try things like this :
render_to_string(text: template, locals: locals, template: "pdf_template")
And
render_to_string(inline: template, locals: locals, template: "pdf_template")
But doing so, it suddenly can't find the template and returns :
ActionView::MissingTemplate: Missing template layouts/pdf_template with {:handlers=>[:erb, :builder, :coffee, :haml], :formats=>[:pdf], :locale=>[:en, :en]}. Searched in:
* "/Users/elephanttrip/Sites/shasta/app/views"
Which is strange because it worked fine in its current location and definition.

If you want to store your views in the database, you should use another rendering engine rather than in Rails by default. Check liquid gem (http://railscasts.com/episodes/118-liquid, http://rubygems.org/gems/liquid).
For example, we use this gem to render emails for our maillists (their templates are stored in the DB).

Related

Rails 6.1.4 Deprecation warning: Rendering actions with '.'

I'm receiving a deprecation warning when running rails test. That warning being below. Any help is appreciated in identifying what I'm doing incorrectly.
(Edit: Side note, the render MUST break and return from the current controller call. I attempted to use ApplicationController.render(...) in place of the current render call, but that did not return from the controller call and I was receiving errors/warnings of :no_content rendered.)
Warning:
DEPRECATION WARNING: Rendering actions with '.' in the name is deprecated: actions/action_success.json (called from update at /<path>/app/controllers/table_base_controller.rb:39)
The code throwing the warning is specifically this call to render within a controller:
render('/actions/action_success.json', locals: {
view: action.lookup_view('default'),
action: action,
area: current_area,
account: current_account
})
I've tried taking off the .json as directed (also tried adding template: <path>, tried file: <path>), however, I receive this error in the test console:
Error:
TableControllerTest#test_Admin_should_update_via_loan_table:
ActionView::MissingTemplate: Missing template actions/action_success with {:locale=>[:en], :formats=>[:html], :variants=>[], :handlers=>[:raw, :erb, :html, :builder, :ruby, :jbuilder]}. Searched in:
* "/<path>/app/views"
app/controllers/table_base_controller.rb:39:in `update'
app/controllers/application_controller.rb:79:in `with_account'
test/controllers/table_controller_test.rb:14:in `block in <class:TableControllerTest>'
The file in question (path: app/views/actions/action_success.json.jbuilder):
# frozen_string_literal: true
json.status 'success'
json.status_code 200
json.messages action.messages
if view
json.result do
json.partial! view.to_s, result: action.result, locals: { area: area }
end
else
json.result action.result
end
Deprecating partial names that include a . was done to prevent ambiguity in parsing the partial name. We should explicitly state formats instead of including them in the partial name we pass to render.
Without the format in the string you pass in, you need to ensure the formats the render is expecting includes the format you're using, in this case json, which is not one of the default formats.
You can send it in as an option (and make the partial name an option as well) like this:
render(
partial: '/actions/action_success',
formats: [:json],
locals: {
view: action.lookup_view('default'),
action: action,
area: current_area,
account: current_account
}
)

Render a partial layout in rails

I am trying to build a demo app like square space. I have a preview page where an iframe loads the template that was selected. So I decided that I wont be needing the default layout (application.html.erb). I created a new folder called Design1 in views and inside it created another folder called partials. I made _header.html.erb inside of it. I created another file called home.blade.php inside the Design1 folder and tried to include the 'layouts/header' in it and it gives me this err
Missing partial Design1/_header with {:locale=>[:en], :formats=>[:html], :variants=>[], :handlers=>[:erb, :builder, :raw, :ruby, :coffee, :jbuilder]}. Searched in: * "/usr/share/nginx/html/fuitter-test/app/views"
this is how I am rendering the header file in home.html.erb
<%= render 'layouts/header' %>
my forlder structuer
views
-Design1
-layouts
- _header.html.erb
-home.html.erb
-other folders
And I have also done
layout false
in the controller
First of all - always downcase on file names! Never use Design or MyCoolStory, in rails we use convention over configuration and that means snake_case which is everything downcased and separated with _under_scores
To your render issues:
There is a great documentation where you'll find anything you need: http://guides.rubyonrails.org/layouts_and_rendering.html
Let me help you a little.
Rails is looking for a Layout. By default it will be expected in /app/views/layouts/application.html.erb (there is nothing wrong with keeping it named as application). A Layout is the whole HTML Frame you will need. Within the Layout there (should) always be a yieldblock.
A YieldBlock in rails is where your templates are rendered into.
so basically a layout-file can look like this (i use haml for easier reading)
%html
%head
=render "shared/head"
%body
.wrapper
%nav.navigation=render "shared/navigation"
.main_content
=yield
%footer.foot=render "shared/footer"
This means you are having 3 partial-templates in /app/views/shared named _head.html.erb, _navigation.html.erb and _footer.html.erb
That's the rails way.
Further informations
If you are planning to have a multi-design app, you should structure your views in total like
/app/views/design1
/app/views/design2
/app/views/design3
/app/views/shared
and set the lookup path in your controller like this
prepend_view_path "#{Rails.root}/app/views/#{design_path}"
def design_path
current_page.design_name
end
By then, all views will be looked up into their specified folder (Spree multi_store engine, is doing like this, for an example)
You put your layouts folder in Design1 folder, thus you should use following path to render your layout:
<%= render 'Design1/layouts/header' %>
The render structure should be starting from the /views folder.
<%= render 'Design1/layouts/header' %>

Why I am getting missing template from a subdirectory?

I have the following in my views/patients/show.html.slim
== render 'era/header'
Of course, views/patients/era/_header.html.slim exists, though it throws a missing template error:
ActionView::MissingTemplate at /patients/12345
Missing partial era/header with {:locale=>[:en], :formats=>[:html], :handlers=>[:erb, :builder, :raw, :ruby, :coffee, :slim, :haml]}.
Searched in: * "/home/pablo/code/rails/tarjira/app/views"
If I use == render 'patients/era/header' works, same with == render 'era_header' (assuming I have a views/patients/_era_header.html.slim file). The latter makes me think that rails search the actual directory (views/patients), so I don't understand why in the first case I have to prefix with patients/.
I'm using Rails 4.0.4.
To render a partial as part of a view, you use the render method within the view:
== render 'era_header'
This will render a file named _era_header.html.slim at that point within the view being rendered.
== render 'era/header'
This code will pull in the partial from app/views/era/_header.html.slim. Notice how the Rails is forming the path i.e, by prefixing app/views before the given path in render method call i.e., era/header. This is how render method is implemented in Rails.
Read the Rails Guide explanation for Naming Partials
The desire for partial rendering with relative paths seems to have a long history. There's an issue from 2011 and a pull request from 2015.
For now if you just need 1 extra level as described in your question you can place a callback in your application_controller.rb:
class ApplicationController < ActionController::Base
before_action :_append_view_path
def _append_view_path
append_view_path("app/views/#{controller_path}")
end
end
This way your views will gain the ability to use render('subfolder/partial') instead of render('controller/subfolder/partial').

Embedding JSON into HTML with Rails3 and Rabl

I'm following the #322 RailsCasts and in the last part he comments a way to embebed json into html
<div id="articles" data-articles="<%= render(template: "articles/index.json.rabl") %>" >
In my project I have a rabl template: app/views/places/show.json.rabl
object #place
attributes :id, :name, :desc, :address
node(:type) { |place| place.type_place.name }
child :photos do
attributes :id, :desc
node(:url) { |photo| photo.image.url(:square) }
end
If I render /places/21.json it shows:
{"id":21,"name":"foo","desc":"bar","address":"some address","type":"baz",
"photos":[{"id":26,"desc":"foofoo","url":"/uploads/photo/image/26/square_conmemorativo-1920x1080.jpg"}]}
well it's working but if I try to embebed json data into html I'm doing this:
<article id="show_place" data-place="<%= render(template: "places/#{#place.id}.json.rabl") %>" >
error log
Missing template places/21.json with {:locale=>[:en],
:formats=>[:html], :handlers=>[:erb, :builder, :coffee, :rabl]}.
Searched in: * "/home/ed/projects/rails_projects/final_u/app/views"
What Am I doing wrong?
UPDATE
I just found the solution
<article id="show_place" data-place="<%= render(template: "places/show.json.rabl") %>" >
And it works but I don't know why.. and here I have another question
There is a way to pass a single object to the render(template: "") ??
Thanks in advance.... and sorry for my English
The reason behind this is convention for render. The function expects the template itself to render, not the route (which is what you're typing into your URL bar).
If you enter /places/21.json into your URL bar in your browser, it will call the places controller with the parameters of id = 21 and format = json.
It will then render the appropriately named view (Which in this case will be your RABL template) at the end of the function defined in your controller.
That template then renders it's data from the value of the #place variable defined on the first line.
I'm assuming your controller sets the #place variable with params[:id] or something similar.
When you call render you are essentially manually doing the last part that the controller function automatically does for you: Displaying a template.
You then should specify what template you wish to render, making sure any variables are set before hand.
So the reason why places/show.json.rabl works is simply because you are rendering the appropriately named template. This will render the show template under your places folder inside views.
It will then use the #place variable I assume you've defined in earlier in your controller or view.
TL;DR
You did the right thing at the end by rendering the template. You can render a different object by changing the variable the template uses on it's first line.

Rails 3.1.0 kaminari ActionView::Template::Error inside ajax request?

I'm trying to render my pagination links inside an ajax request with kaminari and im getting a server error. I'm using the render_to_string method to render the pagination links to a string then parse it via json. I'm using rails 3.1.0.
ActionView::Template::Error (Missing partial kaminari/paginator with {:handlers=>[:erb, :builder, :haml], :formats=>[:json], :locale=>[:en, :en]}. Searched in:
Basically it's looking for the partials in all my load paths and can't seem to find the files, and they're there for sure.
Has anyone experienced similar behavior and know of a possible reason?
I just ran into this as well. I was able to work around it by moving render_to_string into a respond_to block -
respond_to do |format|
format.js do
foo = render_to_string(:partial => 'some_kaminari_view').to_json
render :js => "$('#foo').html(#{foo})"
end
end
See here: http://whowish-programming.blogspot.com/2011/07/stupid-rails3-with-missing-template-and.html
Just append .html to your view name.

Resources