Render output of HTML stored in database in Rails - ruby-on-rails

I have some html content stored in a database field. I would like trusted admins in our system to be able to edit the HTML when needed. Eventually this html will be converted into an email message and sent to users. In addition to the static html content, the email message has a first and last name that is stored in an active record model.
I was hoping to leave the <%= user.firstname user.lastname %> inside the HTML text when the admins are editing the content and then eventally combine the content with embedded erb the email renderer. I have the part where the admins can save the HTML working fine.
However, even ignoring the email and just trying to render to a normal web page, I am not able to get a view to correctly substitute the embedded <%= ... %> with the information from the database. I always see the <%= ... %> instead of the substituted text. I have tried render_to_string, render :inline, etc.
In summary, I am trying to:
Take some html text with embedded some erb from the database
Run the text through a template where the embedded erb is replaced with the variables passed into locals
Take the resulting text block and either email it to users or display on a web page depending on my needs
The problem is that the results always have the <%= ... %> in it instead of the substitutions.
In an example controller I have:
def showit
#storedhtml = mymodel.savedhtml
#emailtext = render_to_string( template: 'e.html.erb',
layout: false, locals: { user:#user })
end
The e.html.erb contains:
<%= raw #storedhtml %>
and the showit.html.erb has:
= raw #emailtext
I have also tried using inline like this:
def showit
# the line below is substituted but the <p> tags are not converted
#stuff = "<%= '<p>testme</p>' + user.firstname %>"
#storedhtml = mymodel.the_html_content
#output = render( inline: #storedhtml, locals: { user:#user }, layout: true )
end

In a controller you wouldn't use Erb syntax, you'd use normal Ruby string interpolation:
#stuff = "#{'<p>testme</p>'} #{user.firstname}"
# Or, since the HTML isn't dynamic:
#stuff = "<p>testme</p> #{user.firstname}"
And to output it in the view you'd need to use html_safe:
<%= #stuff.html_safe %>
In general, generating HTML directly in the controller isn't a great idea since there are other mechanisms in place, and it creates another place to look when you're trying to figure out what component creates which HTML.
Edit I misunderstood. Another templating engine like Sameera suggested is one option, or just evaluate the DB value as an erb template using your current binding.
You could also create a template resolution component that would allow retrieval directly from the DB if no file is found; the Crafting Rails Applications book discusses this.

I guess what you need is 'liquid' - it's a template language for Rails.
Check this out:
http://liquidmarkup.org/
http://railscasts.com/episodes/118-liquid

Assuming you have a Model with attribute named "template" which returns some html template (with ERB), if you want to render it you can use something like this into your controller's action:
render inline:"<%= raw ERB.new(#your_var.template).result(binding) %>".html_safe, layout:'application'

Related

Rendering an image from the Unsplash API in Rails

I have extensively researched this matter both on Stack Overflow and Google but found nothing conclusive. Since I'm completely new to the concept of API usage within Rails I have to ask for some advice.
I have followed the procedure from the github page
I have included the Unsplash helper in application_helper.rb as follows
def show_photo
Unsplash::Photo.find("tAKXap853rY")
end
and simply added
<%= image_tag show_photo %>
in my view.
This returns an object (So connectivity is good)
<img src="/images/#<Unsplash::Photo:0x007fc4b2f953c0>" alt="#
<unsplash::photo:0x007fc4b2f953c0>">
I'm aware that Rails is looking for a picture in the assets/images folder
How do I parse the inbound JSON and render it in my Rails view?
You can access to the urls key within the OpenStruct attributes in the Photo object that includes the raw, full, regular, small and thumb sizes, also as keys.
So, just to test you could use the raw one, like:
<%= image_tag Unsplash::Photo.find('tAKXap853rY')[:urls][:raw] %>
Or I think you could modify your method to accept one parameter which is the size key of the image, like:
module ApplicationHelper
def show_photo(size)
Unsplash::Photo.find("tAKXap853rY")[:urls][size.to_sym]
end
end
Then:
<%= show_photo('raw') %> # 'full', 'regular', etc ...
further to this solution I am trying to display the photographer's name by using the user.name method.
In the console I can get the following :
photo = Unsplash::Photo.find("tAKXap853rY")
photo.user.name
will return
=> "Alejandro Escamilla".
But in RAILS :
def show_photo(size)
#photo =Unsplash::Photo.find("tAKXap853rY")[:urls][size.to_sym]
end
just trying to display the name in my view like:
<%= #photo.user.name %> will return "user undefined method".
The .user.name is accessible in the console but not in rails! What have I missed? Thanks

Why render_to_string messes up the page?

I've got a controller that gets some data from the database and an html view is rendered nicely in my browser.
Now I need to bootstrap some json in my html (to be used by javascript).
I add the following code to render json in the controller:
#my_json = render_to_string(template: 'dimension_types/index.json.jbuilder')
I do nothing else, just add this code to my controller and what happens is that the browser now just shows my page's html code. In the html source my page is wrapped in <pre></pre> tags.
There's no error in the logs. I tried adding layout: false, passing various combinations of handlers and formats to render -- nothing changes.
What am I doing wrong? What part of the documentation am I missing?
I also came across this problem. There might be a better way to do this, but here is a semi-hack that will work:
# the_controller.rb
def your_action
#...
#json_string = render_to_string(template: 'a_template', formats: [:json])
# reset the content type header
response.headers["Content-Type"] = 'text/html'
#...
end
The next piece of code shows how I made use of the JSON string in my view. If the JSON contains user-generated data, you will want to more thoroughly sanitize it to prevent XSS security risk (more info: https://stackoverflow.com/a/10390313/111635). The JSON I am generating doesn't have this problem, so I just used html_safe:
# the_view.html.erb
# ... bunch of ERB code ...
<%= javascript_tag do %>
$(document).ready(function() {
do_stuff_with_json(<%= #json_string.html_safe %>);
});
<% end %>

Render html.erb (not partial) in other html.erb

I'm quite new to Rails and trying to make app with Foundation framework. The problem is with modal window.
I have an index.html.erb file in views/users folder, generated by scaffold.
Also there is a new.html.erb file in the same folder.
I want to open ../users/new link in modal window on index page.
I used examples in Reveal (Foundation Documentation), put new.html.erb file content in:
<div id="myModal" class="reveal-modal">
.
.
</div>
Also, add to New User link "href" attribute.
<%= link_to 'New User', new_user_path, 'data-reveal-id' => 'myModal' %>
as was described here.
Now I need to render new.html.erb in index.html.erb, cause I need this code just before /body tag, as described in Foundation Docs.
I've tried to render it as partial, but it doesn't work.
Is there any way to do it, without double new.html.erb as _new.html.erb and inserting it as partial in index.html.erb?
I don't think, that RoR with all there's "Write less code!" stuff, doesn't have the way for do it without code duplicating.
Thanks!
You cannot use the new action as it is, though you can put your form in one partial, use across new and your action to generate form in modal.
On Page load you can use _form partial.
You can use ajax to generate the form for the model if you want on fly, this can be use for edit as well as new.
Step1 :link_to "your action path", remote: true, id: "abc"
Step2: your action path should return html of the form using render to string
Step3: now using jquery ajax success of $("#abc") replace your model inner content with the form.
And use the create action for both ajax and postback.
Code is DRY.
Let me know if you need the code.
Thanks

Rails: What does it actually mean to "render a template"

I've become a bit confused about the idea of "rendering" a "template" due to the way an author speaks about it in a book I'm reading.
My original understanding of "rendering a template" was that it meant that Rails is providing the content that is viewed on the screen/presented to the viewer (in the way that a partial is rendered) but the book I'm reading seems to be using the concept of "rendering a template" to also mean something else. Let me explain in context
This book (rails 3 in action) sets up a page layout using the conventional layouts/application.html.erb file, and then it "yields" to different view pages, such as views/tickets/show.html.erb which adds more content to the screen. that's all straightforward..
Within this view views/tickets/show.html.erb, there is a rendering of a partial (which is also a straightforward concept).
<div id='tags'><%= render #ticket.tags %></div>
Now within this partial there is, using ajax, a call to a "remove" method in the "tags_controller.rb" which is designed to allow authorized users to remove a "tag" from a "ticket" in our mock project management application.
<% if can?(:tag, #ticket.project) || current_user.admin? %>
<%= link_to "x", remove_ticket_tag_path(#ticket, tag),
:remote => true,
:method => :delete,
:html => { :id => "delete-#{tag.name.parameterize}" } %>
<% end %>
Now here is the "remove" action in the tags controller (which disassociates the tag from the ticket in the database)...
def remove
#ticket = Ticket.find(params[:ticket_id])
if can?(:tag, #ticket.project) || current_user.admin?
#tag = Tag.find(params[:id])
#ticket.tags -= [#tag]
#ticket.save
end
end
end
At the end of this remove action, the author originally included render :nothing => true , but then he revised the action because, as he says, "you’re going to get it to render a template." Here's where I get confused
The template that he gets this action to render is "remove.js.erb", which only has one line of jquery inside it, whose purpose is to remove the "tag" from the page (i.e. the tag that the user sees on the screen) now that it has been disassociated from the ticket in the database.
$('#tag-<%= #tag.name.parameterize %>').remove();
When I read "rendering a template" I expect the application to be inserting content into the page, but the template rendered by the "remove" action in the controller only calls a jquery function that removes one element from the page.
If a "template" is "rendered", I'm expecting another template to be removed (in order to make room for the new template), or I'm expecting content to be "rendered" in the way that a partial is rendered. Can you clarify what is actually happening when a "template" is "rendered" in the situation with the jquery in this question? Is it actually putting a new page in front of the user (I expected some sort of physical page to be rendered)
You're nearly there! Rendering a template is indeed always about producing content, but for a slightly wider description of content. It could be a chunk of html, for example an ajax call to get new items might produce some html describing the new items, but it doesn't have to be.
A template might produce javascript as it does in your second example. Personally I am trying to avoid this and instead pass JSON back to the client and let the client side js perform the required work.
Another type of rendering you might perform is to produce some JSON. APIs will often do this, but you might also do this on a normal page. For example rather than rendering some javascript to delete tag x you might render the json
{ to_delete: "tag-123"}
and then have your jQuery success callback use that payload to know which element to remove from the DOM, by having this in your application.js file
$('a.delete_tag').live('ajax:success', function(data){
var selector = '#' + data.to_delete;
$(selector).remove()
}
(Assuming that your delete links had the class 'delete_tag')
Rendering JSON like this isn't really a template at all, since you'd usually do this via
render :json => {:to_delete => "tag-#{#tag.name.parameterize}"}
although I suppose you could use an erb template for this (I can't imagine why though).
My understanding is that js.erb is "rendered" by executing the javascript functions within it. Very often something like the below is done:
jQuery(document).ready(function() {
jQuery('#element').html('<%= escape_javascript(render pages/content) %>');
});
There's a really succinct overview of rendering at http://guides.rubyonrails.org/layouts_and_rendering.html that may help as it also goes into the details of the ActionController::Base#render method and what happens behind the scenes when you use render :nothing (for example). Render but can be used for files or inline code as well -- not just 'templates' in the traditional sense.

Ruby On Rails: using arrays with link_to

I was curious on how to use arrays in the link_to method in ruby on rails for example:
Controller:
def index
#test = [1,2,3]
end
View:
<%= link_to "test", {:action => 'index'}, :test => #test %>
When looking at the source then, I end up with something to the effect of:
test
My guess is that the array's to_string or something similar is getting called to set the value of test in the html.
My goal is to be able to have a form in which people can submit data on the page, and then once they've submitted the data and return to the page, if they click on the link the data will persist through clicking on the link.
*Ideally I would like to do this without having to pass the parameters in the url.
Thank you.
If you want to keep data you should probably use cookies. They are very easy to use, just assign a value with the following in the action:
cookies[:some_key] = "some value"
and retrieve it with this:
cookies[:some_key] # returns "some value"
However, just to clarify what link_to is doing in your example:
<%= link_to "test", {:action => 'index'}, :test => #test %>
When looking at the source then, I end up with something to the effect of:
test
The reason is that you are passing #test to the third argument in link_to, which is a hash of html attributes, hence why it's turned into one. To have it become an parameter on the link, you need to pass it with the second, eg, {:action => 'index', :text => #test}. As noted above, however, this is not necessarily the best way to tackle this and, in addition, it's usually best to also pass the controller name to link_to or, better yet, use a named route.
If I understand well, you want to keep the datas submitted by the user after they validate the form ?
Well Rails is able to do that without any of your code line needed.
Based on the supposition that you have a route resource "objects"
In your controller :
def edit
#object = Object.find_by_id params[:id]
end
def update
#object = Object.find_by_id params[:id]
if #object.update_attributes params[:object]
# The datas have been successfully saved. You redirect wherever you want to.
else
render :action => 'edit'
end
end
and in your view :
<% form_for #object do |f| %>
<%= text_field :name %>
<% end %>
When the form fails to validate, the "name" text field automatically gets the previous entered data.
If after that you still need to reload your datas, you don't need to add them as a parameter in a link tag.
You get the object in your controller and passes it's datas to the view where you display it.
I would just write a view helper that formats it into a string with good separators, like commas.
That isn't a good way to be passing along information though. Try session variables, cookies, or url-encoded variables instead.
The best match to what you are doing would be url-encoded variables, which will show up in a form similar to this:
test
My guess is that it is using Array#join.
You could try something like
:test => #test.join( ',' )
and then parse the string in your controller. But it is somewhat error prone if the user enters the same character you chose as delimiter.
But, assuming the linked page is also served by Rails, I think the best solution would be to use the flash area to store the results on the server
flash[ :submitted_params ] = params;
and in the controller for the linked page
old_params = flash[ :submitted_params ] || {}

Resources