Exclude part of a string when testing in rails - ruby-on-rails

How would I take a test statement that tests for two equal strings, such as, if #current_lesson.code == #current_course.answer, and exclude some parts of the answer. So, if I want to make the user write a <p> tag with anything in it, how would I make it correct, as long as they have the <p> tag?

I would use Regexp to check if you have a <p> tag with text inside the string. If you use Rspec, i'd use the matches matcher.
The code would be something like this:
expect(#current_lesson.code).to match(/\<p\>.+\<\/p\>/)
Didnt check the regexp, it is just to prove a point :).

You can use the "include" method for string object:
Example :
if #current_course.answer.include? #current_lesson.code
#Your code logic here
end

Related

Testing a Rails helper method that returns HTML, compare with plain text

I have this Rails helper method that returns text with links inside it:
def add_to_library_event_text(event)
user_link = link_to(event.user.username, user_path(event.user))
game_link = link_to(event.game_purchase.game.name, game_path(event.game_purchase.game))
return user_link + " added " + game_link + " to their library."
end
What I want to do is write a spec for it, to make sure it outputs the right text. I don't care much about the exact details of the HTML, and I'd prefer to do this in a helper spec rather than a feature/browser spec since it's much faster.
I have a working test already, it looks like this:
expect(helper.add_to_library_event_text(add_to_library_event)).to eq \
"#{user.username} added #{game.name} to their library."
I'm hoping there's some way that I haven't found yet that will allow me to strip out the HTML from this, so I can write a comparison like this:
expect(helper.add_to_library_event_text(add_to_library_event)).to eq \
"#{user.username} added #{game.name} to their library."
Is there anything in RSpec/Rails that'd allow me to strip the HTML from this?
I figured out how to do this! I use strip_tags to strip the HTML from the input string.
expect(
strip_tags(helper.add_to_library_event_text(game_purchase_library_event))
).to eq "#{user.username} added #{game.name} to their library."
https://api.rubyonrails.org/classes/ActionView/Helpers/SanitizeHelper.html#method-i-strip_tags
You could also use the sanitize(html_string_goes_here, tags: []) method, but this is simpler as far as I can tell.
When I want to match particular text within any complex markup (such as HTML), I like to use match or include, something like this:
expect(output).to include "#{user.username} added #{game.name} to their library."
or...
expect(output).to match /#{user.username} added #{game.name} to their library./
This cuts to the essence of what you're testing, and is very resilient to changes in markup, focusing on the content.

How can I put a link inside of a text string in HAML?

This should probably be easier than it is. I just want to put a link inside an HTML paragraph element.
%p{class: "answer"}="Please upload your data to this portal in text (tab-separated) format. Download our template #{raw(link_to 'here', '/templates/upload_template.xlsx')} for sample data and a description of each column."
Rails is encoding the tag information. I don't want tags to be encoded. I want them to be tags.
You can use more than one line inside any block, to solve your problem we will have something like this:
%p{class: "answer"}
Please upload your data to this portal in text (tab-separated) format. Download our template
= link_to 'here', '/templates/upload_template.xlsx'
for sample data and a description of each column."
You can use interpolation directly in Haml, and doing this seems to fix the issue in this case.
So instead of doing this:
%p= "Text with #{something_interpolated} in it."
you can just do
%p Text with #{something_interpolated} in it.
i.e. you don’t need the = or the quotes, since you are just adding a single string. You shouldn’t need to use raw either.
(Also, note you can do %p.answer to set the class attribute, which may be cleaner if the value isn’t being set dynamically.)
Why this is being escaped here is a different matter. I would have expected the two cases (%p= "#{foo}" and %p #{foo}) to behave the same way. However, after a bit of research, this behaviour seems to match how Rails behaves with Erb.

How to output html_safe within <%=%> block while concatenating strings?

Consider this:
<%
str = "http://domain.com/?foo=1&bar=2"
%>
Now these cases:
<%=str%>
# output:http://domain.com/?foo=1&bar=2
<%=str.html_safe%>
# output:http://domain.com/?foo=1&bar=2
<%="#{str.html_safe}"%>
# output:http://domain.com/?foo=1&bar=2
<%=""+str.html_safe%>
# output:http://domain.com/?foo=1&bar=2
I need to output the URL with other strings. How can I guarantee that the ampersand will be unescaped? For reasons beyond my control I can't send &.
Please help! Pulling my hair here :\
EDIT: To clarify, I actually have an array like so:
#images = [{:id=>"fooid",:url=>"http://domain.com/?foo=1&bar=2"},...]
I am creating a JS array (the image_array var) to use in my app this way:
image_array.push(<%=#images.map{|x|"{id:'#{x[:id]}',url:'#{x[:url].html_safe}'}"}.join(",")%>);
This generates:
image_array.push({id:'fooid',url:'http://domain.com/?foo=1&bar=2'},...);
Which does not work in my specific case. I need the url without the amp; part.
When you write:
"#{foo.bar}"
this is ~equivalent to writing
foo.bar.to_s
So what you are actually doing is:
<%=str.html_safe.to_s%>
…which Rails no longer sees as being safe, and so it hits your resulting string with a round of HTML escaping.
I don't know the internals of Rails, but I assume that the html_safe method extends the string object with an instance variable flagging it as OK, but when you wrap that in another string via interpolation you are getting a new string without that flag.
Edit: To answer your needs, use raw or call html_safe on your final string:
<%=raw "foo#{str}"%>
<%="foo#{str}".html_safe%>
or in your case:
image_array.push(<%=raw #images.map{…}.join(',')%>);
image_array.push(<%=#images.map{…}.join(',').html_safe%>);
See also this question.
Use this
<%=str.html_safe.to_s%>
or
<%=raw(str)%>
give you better results
image_array.push(<%= #images.map{|x| "{id:'#{x[:id]}',url:'#{x[:url]}'}".html_safe }.join(",") %>);
what you would do to be safe is:
image_array.push(<%= #images.map { |image| image.as_json(only: [:id, :url]) }.to_json } %>)
this will escape the <, >, etc. properly like this:
[{"name":"\u003ch1\u003eAAAA\u003c/h1\u003e"}]
and for people coming here like me who want to concatenate strings, it's just not safe to do it, the best way is to concatenate tags, e.g.
content_tag(:p) do
content_tag(:span, "<script>alert(1)</script>") +
link_to("show", user)
end
will work fine and properly escape the first string

Extracting email addresses in an html block in ruby/rails

I am creating a parser that wards off against spamming and harvesting of emails from a block of text that comes from tinyMCE (so it may or may not have html tags in it)
I've tried regexes and so far this has been successful:
/\b[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}\b/i
problem is, i need to ignore all email addresses with mailto hrefs. for example:
test#mail.com
should only return the second email add.
To get a background of what im doing, im reversing the email addresses in a block so the above example would look like this:
moc.liam#tset
problem with my current regex is that it also replaces the one in href. Is there a way for me to do this with a single regex? Or do i have to check for one then the other? Is there a way for me to do this just by using gsub or do I have to use some nokogiri/hpricot magicks and whatnot to parse the mailtos? Thanks in advance!
Here were my references btw:
so.com/questions/504860/extract-email-addresses-from-a-block-of-text
so.com/questions/1376149/regexp-for-extracting-a-mailto-address
im also testing using this:
http://rubular.com/
edit
here's my current helper code:
def email_obfuscator(text)
text.gsub(/\b[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}\b/i) { |m|
m = "<span class='anti-spam'>#{m.reverse}</span>"
}
end
which results in this:
<a target="_self" href="mailto:<span class='anti-spam'>moc.liamg#tset</span>"><span class="anti-spam">moc.liamg#tset</span></a>
Another option if lookbehind doesn't work:
/\b(mailto:)?([A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4})\b/i
This would match all emails, then you can manually check if first captured group is "mailto:" then skip this match.
Would this work?
/\b(?<!mailto:)[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}\b/i
The (?<!mailto:) is a negative lookbehind, which will ignore any matches starting with mailto:
I don't have Ruby set up at work, unfortunately, but it worked with PHP when I tested it...
Why not just store all the matched emails in an array and remove any duplicates? You can do this easily with the ruby standard library and (I imagine) it's probably quicker/more maintainable than adding more complexity to your regex.
emails = ["email_one#example.com", "email_one#example.com", "email_two#example.com"]
emails.uniq # => ["email_one#example.com", "email_two#example.com"]

I am creating a Twitter clone in Ruby On Rails, how do I code it so that the '#...''s in the 'tweets' turn into links?

I am somewhat of a Rails newbie so bear with me, I have most of the application figured out except for this one part.
def linkup_mentions_and_hashtags(text)
text.gsub!(/#([\w]+)(\W)?/, '#\1\2')
text.gsub!(/#([\w]+)(\W)?/, '#\1\2')
text
end
I found this example here: http://github.com/jnunemaker/twitter-app
The link to the helper method: http://github.com/jnunemaker/twitter-app/blob/master/app/helpers/statuses_helper.rb
Perhaps you could use Regular Expressions to look for "#..." and then replace the matches with the corresponding link?
You could use a regular expression to search for #sometext{whitespace_or_endofstring}
You can use regular expressions, i don't know ruby but the code should be almost exactly as my example:
Regex.Replace("this is an example #AlbertEin",
"(?<type>[##])(?<nick>\\w{1,}[^ ])",
"${type}${nick}");
This example would return
this is an example <a href="http://twitter.com/AlbertEin>#AlbertEin</a>
If you run it on .NET
The regex (?<type>[##])(?<nick>\\w{1,}[^ ]) means, capture and name it TYPE the text that starts with # or #, and then capture and name it NAME the text that follows that contains at least one text character until you fin a white space.
Perhaps you can use a regular expression to parse out the words starting with #, then update the string at that location with the proper link.
This regular expression will give you words starting with # symbols, but you might have to tweak it:
\#[\S]+\
You would use a regular expression to search for #username and then turn that to the corresponding link.
I use the following for the # in PHP:
$ret = preg_replace("#(^|[\n ])#([^ \"\t\n\r<]*)#ise",
"'\\1<a href=\"http://www.twitter.com/\\2\" >#\\2</a>'",
$ret);
I've also been working on this, I'm not sure that it's 100% perfect, but it seems to work:
def auto_link_twitter(txt, options = {:target => "_blank"})
txt.scan(/(^|\W|\s+)(#|#)(\w{1,25})/).each do |match|
if match[1] == "#"
txt.gsub!(/##{match.last}/, link_to("##{match.last}", "http://twitter.com/search/?q=##{match.last}", options))
elsif match[1] == "#"
txt.gsub!(/##{match.last}/, link_to("##{match.last}", "http://twitter.com/#{match.last}", options))
end
end
txt
end
I pieced it together with some google searching and some reading up on String.scan in the api docs.

Resources