0

Answer at the end.

I currently refactoring my app, and I'm wondering how to short my "if" since I use them a lot in it :

What I want, is a line break <br /> only if the value isn't blank, so, for now I'm writing it this way :

<% if @card.address.street.present? %>
 <%= @card.address.street.titleize %>
 <%= tag(:br) %> ## or plain html <br />
<% end %>

It works well, but I'm sure there is a less wordy way.

I tried :

<%= @card.address.street.titleize + tag(:br) if @card.address.street.present? %>

==> Washington Road '' ## br tag ain't html_safed.

if I do :

<%= raw @card.address.street.titleize + tag(:br) if @card.address.street.present? %>

Which is equal to :

<%== @card.address.street.titleize + tag(:br) if @card.address.street.present? %>

I works well, but expose my code to XSS attack.

So, I tried :

<%= @card.address.street.titleize + raw(tag(:br)) if @card.address.street.present? %>

<%= @card.address.street.titleize + tag(:br).html_safe if @card.address.street.present? %>

<%= @card.address.street.titleize + "<br />".html_safe if @card.address.street.present? %>

==> Washington Road '' ## br tag still ain't html_safed.

Sanitize give good result on this, used like that :

<%= sanitize(@card.address.street.titleize + tag(:br)) if @card.address.street.present? %>

But is this the best way to go regarding performance?

I ended up using an helper:

Inside helpers/application_helper

def line_break value
 sanitize(value) + tag(:br)
end

Helper is loaded inside controller

class UsersController < ApplicationController
helper ApplicationHelper

I added this helper inside application one. If you want something less general on your app, a module would be prefered.

Sanitize used with empty parameters will check for html inside your string, and delete it. If you want something less heavy, you can use h() that will escape all html instead of removing it.

In the view

<%= line_break(@card.address.street.titleize) if @card.address.street.present? %>

I know it's purely a "writing speed issue" but any help would be appreciated.

Kind Regards

Mene
  • 344
  • 2
  • 14
  • 1
    This should be in a helper anyway. – Dave Newton Aug 02 '14 at 16:13
  • Sure Dave, and I will use a helper. My issue is mostly the
    not escaped, even if I do a helper, say line_break(@card.address.street.titleize) with def line_break(value) value + tag(:br) end
    – Mene Aug 02 '14 at 16:21

2 Answers2

1

This is not because your br tag is safe or unsafe.

The street string is unsafe and when you add a safe string to an unsafe string then the result is still unsafe.

You could instead write this as

<%= h(@card.address.street.titleize) + tag(:br) %>

The h does the escaping and marks the result as safe (since it has just been escaped).

Frederick Cheung
  • 83,189
  • 8
  • 152
  • 174
  • Since I'm in rails 4, and the sanitize method seems to be pretty, I ended up using <%= sanitize(@card.address.street.titleize) + tag(:br) %> Empty parameters makes the check then remove all attempt to inject html by deleting them instead of escaping them. It fits my need, but the logic of unsafe+safe = unsafe wasn't clear for me yet, so thank you for the hint. – Mene Aug 04 '14 at 08:44
  • Thanks. Tried many, but this is the only thing that does work. – Sri Harsha Kappala Oct 19 '16 at 06:31
0

Try it out:

<% street = @card.address.street %>
<%= h(street.titleize) + tag(:br) if street.present? %>

OR (less readable but compact)

<%= (h(street.titleize) + tag(:br)) if ((street = @card.address.street) && street.present?) %>

Good Luck!

Edit: As Frederick Cheung's comment brings my attention to xss attack associated with html_safe, I have updated the answer and using h for escape, Frederick. I could delete this answer, but its also showing code reduction, so may be it can help someone.

Community
  • 1
  • 1
RAJ
  • 9,697
  • 1
  • 33
  • 63
  • 1
    All of these allow xss – Frederick Cheung Aug 02 '14 at 20:18
  • Thanks Raj. Ain't no need to put @card.address.street inside a local variable, <%= h(@card.address.street) + tag(:br) if @card.address.street.present? %> will work fine :) – Mene Aug 04 '14 at 09:03
  • @user3181644 this was for efficiency and to avoid code repetition.. as u can see you are finding `@card.address.street` twice... – RAJ Aug 04 '14 at 11:19
  • Oh ok. I agree that it looks better regarding code repetition. At first look I didn't think about the local variable for efficiency (since the query is already done in my controller), but now that's sounds interesting used this way, something I never did. – Mene Aug 04 '14 at 22:00
  • The compact version doesn't seem to work, I have to specify the global variable outside the if statement, like <%= @card.street.titleize if ((street = @card.address.street) && street.present?) %> – Mene Aug 04 '14 at 22:52
  • dont think so, whats the error in `(h(street.titleize) + tag(:br)) if ((street = @card.address.street) && street.present?)`? – RAJ Aug 05 '14 at 06:29