I have a model called Content with two fields 'before' and 'after'.
Before creating the record, I do some preprocessing on field 'before' and store it in 'after'. No problem here.
Problem is when I load the show page the contents in 'before' display incomplete. I'm trimming white spaces after a period if there are 2 or more...
e.g.
"this is. some text. with many spaces. after the periods."
The view shows me that 'before' looks like this:
"this is. some text. with many spaces. after the periods."
If I look at the .json version the 'before' field contains the original format - why then does the rails view (non-json) present the 'before' as being "trimmed"?
This is my _content.html.erb
<li><%= content.before %></li>
<li><%= content.after %></li>
This is my show.js.erb
$("#main").html("<%= escape_javascript(render #content) %>");
This is the show definition in contents_controller.rb
respond_to :html, :json
def show
#content = Content.find(params[:id])
respond_with(#content)
end
This is the pre-processing in my model content.rb
class Content < ActiveRecord::Base
before_validation :format_params
def format_params
rm_spaces = /\.\s{2,}/ # regex to rm extra spaces
new_format = '. ' # only one space after period
self.after = before.gsub(rm_spaces, new_format)
end
end
And here are some screenshots of what I mean.
Edit
I believe this is the code that is getting executed since I tried Swards recommendation and it did not work.
This is the code for my highlighting function in my contents_helper.rb
def highlight_changes(text)
highlighter = '<span style= "background: yellow">\1</span>'
matcher = /(\.\s{2,})/
text.gsub(matcher, highlighter).html_safe
end
This is the code in show.html.rb
<p>
<strong>Before:</strong>
<!-- call the helper method to highlight changes made -->
<%= highlight_changes #content.before %>
</p>
You can put a .before class on the before li and add this to css to see it as it was entered.
<li class="before"><%= content.before %></li>
<li><%= content.after %></li>
in the css
.before {
white-space: pre;
}
I think it is the browser that omits extra spaces. You can use to make a whitespace instead.
To transform your string you could try
content.before.gsub(' ', ' ').html_safe
This replaces each space with and then tells rails not to escape the html characters ( ).
Warning:If the before field is input by users then using html_safe is dangerous as it could allow users to inject malicious code.
Related
I am trying to get Ruby to search a text for certain characters, such as # and $. I then want to capture the character and the text beside it until there is white space, so if I would put this as text:
Hey, I am a #string and #what are you?
It would return the index at where the #string and #what are. This line only returns if the text has a special character:
<div class='tweet-text'>
<% if feed.text.match(/#\w+/) %>
Hi
<% end %>
</div>
The point here is I want to color the "#" word to a different color. The code is inside ejs. How would I do this?
When you want to highlight or mark one or more phrases in a text then you might want to have a look at the highlight view helper:
For example
<%= highlight('Hey, I am a #string and #what are you?', /#\w+/) %>
will return
Hey, I am a <mark>#string</mark> and <mark>#what</mark> are you?
I'm making a style guide where I output the code on the right that is displayed on the left.
I know that adding %% escapes ERB
I have written a helper that takes the contents of a block and renders the code in two places one showing the html and I want the other to show the source ERB that created the html.
The problem is I get back HTML where I wanted ERB.
The View Code
<%= display_code do %>
<%= link_to "Button", "/style_guide, class: "btn" %>
<% end %>
The Helper Code
module StyleGuideHelper
def display_code(&block)
content = with_output_buffer(&block)
html = ""
html << content_tag(:div, content, class: "rendered-code")
html << content_tag(:div, escape_erb(content), class: "source-code-preview")
html.html_safe
end
def escape_erb(code)
code = code.gsub("%=", "%%=")
end
end
Expected Result
Button <%= link_to "Button", "/style_guide, class: "btn" %>
Actual Result
Button Button
Cheers
The issue is that this helper runs the block (link_to "Button", ...) -- it never sees the source code inside the block, just its output. You could replace escape_erb with h to capture the resulting HTML, but that won't pop back up to the ERB that generated it.
As I see it, your options are:
Break out examples into partials, then make a helper that a) renders the partial and b) displays the underlying file.
Specify your ERB fragments as strings (heredocs?), pass the string into the helper, and have the helper a) evaluate it via ERB.new(string).result(binding) to render the result and b) display the string.
Make the helper determine what part of the view invoked it, then parse the .erb well enough to find the block. Catch is, the precise format of what you see in callers is subject to change without notice due to the way views are compiled.
Make a helper that uses crazy metaprogramming juju to evaluate the block in both an ERB context as well as your own special context that intercepts the code being evaluated and turns it back into markup.
...sorted in approximate order of complexity and odds of success.
This code below will allow you to retrieve the code for a given block.
class ERBSource
ERB = ::ActionView::Template::Handlers::ERB
def self.for(block)
new(block).source
end
attr_reader :block, :file, :line_number
def initialize(block)
#block = block
#file, #line_number = *block.source_location
end
def source
lines = File.readlines(file)
relevant_lines = lines[(line_number - 1)..-1] || []
extract_first_expression(relevant_lines)
end
private
def extract_first_expression(lines)
code = lines.slice[0,1].join # add the first two lines so it has to iterate less
lines.each do |line|
code << line
return code if correct_syntax?(compile_erb(code))
end
raise SyntaxError, "unexpected $end"
end
def correct_syntax?(code)
stderr = $stderr
$stderr.reopen(IO::NULL)
RubyVM::InstructionSequence.compile(code)
$stderr.reopen(stderr)
true
rescue Exception
$stderr.reopen(stderr)
false
end
def compile_erb(code)
ERB.erb_implementation.new(
code,
:escape => false,
:trim => (ERB.erb_trim_mode == "-")
).src
end
end
This is what the helper looks like
module StyleGuideHelper
def render_example(name, &block)
code = ERBSource.for(block)
content_tag(:h2, name) +
content_tag(:div, &block) +
content_tag(:pre, content_tag(:code, code))
end
end
I put together a nested unordered list in a helper method using a string. The code is okay, but I'd prefer to use the content tag method if possible. Here's what I have:
def show_element_content(element_types, site)
last = get_element_type_name(element_types.first.name)
output = "<li>#{last}<ul>"
if last.nil?
raise "ElementReturnedNullException - this shouldn't happen."
else
element_types.each do |ele|
if last != get_element_type_name(ele.name)
last = get_element_type_name(ele.name)
output << "</ul></li><li>#{last}<ul>"
end
output << "<li>#{link_to get_element_content(ele.name), site_element_type_path(site, ele.name)}</li>"
end
output << "</ul></li>"
end
output.html_safe
end
def get_element_type_name(ele)
ele.split(" ")[0]
end
def get_element_content(ele)
words = ele.split(" ")
words[1..words.size].join(" ")
end
The first method is the one i output in the view. Here's what it does:
It splits each element_type by spaces, as there's a sort of category name persay in each one as the first word. Such as City, State or Franchise. Those words are in the higher up LI tags. Like so:
<ul>
<li>City</li>
<li>State</li>
</ul>
Then it loops through each element type, appending each one as a nested list. When the first word changes, it closes that nested list and li tag, to create a new one. The rendered html looks like this:
<ul>
<li>City
<ul>
<li>CTA 1</li>
<li>P1 S1</li>
<li>P1 S2</li>
<li>Sub2</li>
</ul>
</li>
</ul>
How can I do this using content_tag since i open and close the tags based on various conditions? I know it kind of makes sense to categorize these in another model, but to just do that for the presentation layer I think would be overkill.
In my RoR application, user selects an option from a popup and the selected value is passed to hidden fields found in my parent form.
The problem is when passing values containing html characters (e.g. <a href= ""> ) to the parent form.
In my popup, i have a link as follows which passes a value to the main form:
popup code:
<% #users.each do |user| %>
<%= link_to_function "PassValue", "sendValue('"+ user.location+ "')" %>
<% end %>
application.js:
function sendValue(location){
window.opener.document.getElementById('submission_user_attributes_location').value = location;
}
The location value retrieved form the database can contain html chars like '', and this is where my sendValue function is not working.
Please can someone help me on this.
Many many thanks in advance for your help :)
Please do not use obstrusive javascript. Try rewriting this code using non obstrusive javascript and it will prevent you from running into more problems in the future. See this railscast for more info: http://railscasts.com/episodes/205-unobtrusive-javascript
This being said, you could fix your problem by encoding your user.location with URI.encode, or escape quotes manualy or use escape_javascript.
My favorite solution is escape_javascript. From the documentation:
escape_javascript - Escape carrier
returns and single and double quotes
for JavaScript segments.
# File actionpack/lib/action_view/helpers/javascript_helper.rb, line 50
def escape_javascript(javascript)
if javascript
javascript.gsub(/(\\|<\/|\r\n|[\n\r"'])/) { JS_ESCAPE_MAP[$1] }
else
''
end
end
I want to be able to pass multiple messages to the flash hash, inside of my controller, and have them display nicely together, e.g., in a bulleted list. The way I've devised to do this is to create a helper function in my Application Controller, which formats an array into a bulleted list, which I then pass to, in my case, flash[:success]. This is clearly not the Rails Way because, i.a., my bulleted list gets encoded. That is, instead of getting:
Message 1
Message 2
I get:
<ul><li>Message 1</li><li>Message 2</li></ul>
I'm sure I could figure out a way to raw() the output, but isn't there a simple way to get something like this working? Perhaps there's an option to pass to flash[]? Something else?
I used render_to_string and a partial instead of a helper to achieve something similar.
# app/controller/dogs_controller.rb
def create
#dog = Dog.new(params[:dog])
#messages=[]
if #dog.save
#messages << "one"
#messages << "two"
flash[:notice] = render_to_string( :partial => "bulleted_flash")
redirect_to(dogs_path)
else
render :action => 'new
end
end
Then I format the array of flash messages in an HTML list
# app/views/dogs/_bulleted_flash.html.erb
<ol>
<% #messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ol>
Which produces the following HTML
# http://0.0.0.0:3000/dogs
<body>
<div id="flash_notice">
<ul>
<li>one</li>
<li>two</li>
</ul>
</div>
...
</body>
If you need to continue using a helper then I think you need to append the html_safe method to your string to prevent it from being encoded (which rails 3 does by default). Here is a question showing how to use html_safe in a similar fashion
If you are using Rails3, try the raw method.
raw(my_html_string)
And it won't escape the html. Oh, sorry, I just read your last sentence. Check out this information, "Rails 3 flash message problems", it looks like it may be what you are looking for:
http://www.ruby-forum.com/topic/215108
Usually I would ask for more information about your views and layouts in this situation, because scaffolding doesn't display flash[:success] by default.
The way I solve this is to totally redo my flash messages usually, by making the flash[:whatever] an array every time, and in my layout handling that array instead of just the notice. Remember that flash is just a Hash, you're just setting values.
However if you just want to do this with the setup you have now (helper putting the HTML inside the flash[:success]), you can change the way that the flash messages are displayed in your layout file. By default they are just use <%= flash[:success] %>, which automatically escapes HTML. To make it not do that for the flash messages, change it to <%=raw flash[:success] %>