How can I render custom HTML in Spree with Deface - ruby-on-rails

I am replacing some Spree core template code with Deface and it all works well until I try to make it a bit more custom.
Deface::Override.new(
:virtual_path => "spree/shared/_products",
:replace => "span.price",
:text => "<%= link_to truncateproduct.display_price + '<span class=\"purchase-suggestion\">BUY NOW</span>', :length => 20), product, :class => 'price selling', :itemprop => \"price\", :title => product.name + ': ' + product.display_price %>",
:name => "product_price"
)
Above I am aiming to make the price text a link, and also include a 'BUY NOW' text wrapped in a span for individual styling purpose.
This renders this way:
$15.99<span class="purchase-suggestion">BUY NOW</span>
How can I make Deface evaluate the HTML instead of writing the string?
I have tried doing this in two steps by making two different Deface files, one where I swap the span for the link, and another where I add the span to :insert_bottom. It seems to me it is not possible to use Deface to change the same element twice - is this correct?
Solution
Thanks for answer and conversation in channel. This is the solution:
Deface::Override.new(
:virtual_path => "spree/shared/_products",
:replace => "span.price",
:text => "<%=
link_to ('<span>' + product.display_price + '</span> <span class=\"purchase-suggestion\">BUY NOW</span>').html_safe, product,
:class => 'price selling',
:itemprop => 'price',
:title => product.name + ': ' + product.display_price
%>",
:name => "product_price"
)
.truncate was used for no reason, .html_safe did the job.

Your issue here is with truncate. The result is not marked as HTML-safe, so will be subject to the default escaping when used in views, unless wrapped by raw(). Care should be taken if text contains HTML tags or entities, because truncation may produce invalid HTML (such as unbalanced or incomplete tags).
http://apidock.com/rails/ActionView/Helpers/TextHelper/truncate

Related

Rails - Render partial inside Twitter Bootstrap popover

I want to use a Twitter Bootstrap popover to display a user avatar and email address, with the possibility of adding in more details at a later date.
I am having an issue getting the partial to render inside the content field of the link. The view code is below (in HAML).
%span.comment-username
=link_to comment.user_name, "#", "title" => comment.user_name,
"data-content" => "=render 'users/name_popover'",
class: "comment-user-name"
Currently, this will only produce the content code as a string.
Is there a way to do this so the partial will be inserted instead of the code as a string?
You want rails to actually evaluate the content of the string and not just show the string. The easiest way to do that would be:
%span.comment-username
=link_to comment.user_name, "#", "title" => comment.user_name,
"data-content" => "#{render 'users/name_popover'}",
class: "comment-user-name"
That should pass the render statement to rails and render your partial as expected.
Thanks for the answer jrc - it helped me find a solution.
My solution might be useful for other non HAML people like me:
`<%= link_to('Service History' , '#', :class => "popover-history", :rel => "popover", :"data-placement" => "bottom", :title => "Service History", :"data-content" => "#{render 'services/service_history'}") %>`
with
`$(function () {
$('.popover-history').popover({ html : true });
});`

Rails - escape html in helper?

I currently have a simple method in my application_helper.rb file, which is designed to add a link that will add some a new field to a form when clicked. It looks like:
def link_to_add_fields(type, object_form_builder)
link_to type, "#", "data-partial" => h(render(:partial => type + '/form',
:locals => {type.singularize.to_sym => object_form_builder,
:form_actions_visible => false})),
:class => 'add_fields'
end
I'm having a problem with this code, namely that the partial that should be getting added to the data-partial html attribute is being escaped (presumably by quotes somewhere in the rendered html). I was of the understanding that h() should prevent this, but it doesn't seem to be doing so. Can anyone suggest how to escape this?
EDIT: I tried using the html_safe method as described below, but to no avail. I have managed to get it to escape by doing:
"data-partial" => "'" + render(:partial => type + '/form', :locals => {type.singularize.to_sym => object_form_builder, :form_actions_visible => false}) + "'"
but i'm not sure how safe this is?
EDIT 2: escaping using single quotes is no good - although it escapes the html, it outputs the quotes when the partial is rendered, which is not desirable. Still looking for any ideas on how to escape the html successfully when rendering the partial.
Try an .html_safe method
def link_to_add_fields(type, object_form_builder)
link_to type, "#", "data-partial" => h(render(:partial => type + '/form',
:locals => {type.singularize.to_sym => object_form_builder,
:form_actions_visible => false})).html_safe,
:class => 'add_fields'
end

Generic way of using content_tag for multiple elements of the same kind

I want to generate html like,
<label for='field'>
Label Text
<span class='span1'> Some Text 1 </span>
<span class='span2'> Some Text 2 </span>
...
</label>
I want a call a helper such as,
label_for 'field', :label => 'Label Text', :type1 => 'Some Text 1', :type2 => 'Some Text 2'
For which I tried to do something like,
content_tag(:label, opts[:label], :for => field_name) do
['span1', 'span2'].map { |i|
content_tag(:span, opts[i], :class => i) if opts[i] }.compact.joins('+').html_safe
}
end
But this does not work (of course).
['span1', 'span2'] array is fixed and the user has the option of choosing to display as many spans as needed.
How can I solve this problem?
Why not something like this?
def special_label_for(field_name, label_text, span_array)
content_tag "label", :for => field_name do
concat label_text
span_array.each_with_index do |span_content, index|
concat content_tag("span", span_content, :class => "span" + index.to_s)
end
end
end
special_label_for :user_name, "User Name", ["This is the first Span", "And this is the second Span", "Can also have a third span", "Or as many spans as you like"]
Haven't tested this code, may need to add/remove the concat or an html_safe to get it rendering properly in your view.
Similar thing I need mutliple html element in Label. I solved here
http://apidock.com/rails/ActionView/Helpers/FormTagHelper/label_tag#1428-Html-inside-Lable-tag
You can pass parameters to make dynamic
You can even do something like this:
if the given array is list_of_items
list_of_items.map{ |item| content_tag(:span, item) }.join('').html_safe

haml and no javascript? (rails: form_remote_tag and :with parameter)

i am trying to call a remote method to update page content via ajax/js.
either i am too tired already or haml is not parsing the following code correctly to send the value of the query field via prototype. any ideas?
- form_remote_tag(:url => {:controller => "search", :action => "line"},:with => "'query=' + $('query').value" ) do
%input{:type => 'text', :id => 'query'}
%input{:type => 'submit', :value => 'Search'}
thanks a lot!
t
Have you tried a
= form_remote_tag
instead of
- form_remote_tag
I'm new to HAML myself but I was under the impression that you'll need the form tag to be actually generated not just executed...
Try passing the :with as part of the options hash.
- form_remote_tag({ :url => {:controller => "search", :action => "line"}, :with => "'query=' + $('query').value" }) do
If that doesn't work, debug the problem: Look at the generated html. Is the text field with id query the only element in the page with that id? Is the js code correct? Use the Firebug console to ensure $('query').value returns whatever you've entered into the text field.
Still stuck? Add your generated html into your question so we can better help.
EDIT: Your query input tag does not have a name attribute. Without a name, the javascript helper code skips that field when serializing the form fields...also, you do not need the :with code.
%input{:type => 'text', :id => 'query', :name => 'query'}

Problems passing special chars with observe_field

I am working on a rails project. Using the tag observe_field, I am taking text typed into a text area, processing it in a control, and displaying the result in a div (very similar to the preview in stack overflow). Everything works fine until I type certain special chars.
? => causes the variable not to be found in the params object
(pound) => causes an invalid authenticity error
% => stops the div from being updated
& => every thing after the & is no longer passed into the variable on the server.
Is there a way to solve this?
--- code sample ---
this is the view. ( 'postbody' is a text area)
<%= observe_field 'postbody',
:update => 'preview',
:url => {:controller => 'blog', :action => 'textile_to_html'},
:frequency => 0.5,
:with => 'postbody' -%>
this is the controller that is called
def textile_to_html
text = params['postbody']
if text == nil then
#textile_to_html = '<br/>never set'
else
r = RedCloth.new text
#textile_to_html = r.to_html
end
render :layout => false
end
and this is the javascript that is created:
new Form.Element.Observer('postbody', 0.5, function(element, value) {new Ajax.Updater('preview', '/blog/textile_to_html', {asynchronous:true, evalScripts:true, parameters:'postbody=' + value + '&authenticity_token=' + encodeURIComponent('22f7ee12eac9efd418caa0fe76ae9e862025ef97')})})
This is an escaping issue (as stated by others).
You'll want to change your observe_field :with statement to something like:
:with => "'postbody=' + encodeURIComponent(value)"
Then in your controller:
def textile_to_html
text = URI.unescape(params['postbody'])
...
Can you provide a code sample?
More likely than not you'll just need to escape your HTML entities using encodeuri or something like that.
What does the generated Javascript look like?
Sounds (at first glance) like it's not being escaped.

Resources