Under Rails 5.1 I am using Trix to allow users to edit their 'legal conditions'. Then I am trying to sanitize this 'legal' parameter in my controller before the user record is updated, but end up with :
undefined method `sanitize'
Here the code :
params[:user][:legal] = sanitize params[:user][:legal], tags: %w(strong div strong br li ul)
def user_params
params.require(:user).permit(:presentation, :linktowebsite, :legal)
end
Don't see anything different than normal usage shown here : http://api.rubyonrails.org/classes/ActionView/Helpers/SanitizeHelper.html
You are not using sanitize correctly. sanitize is used in the view, not in the controller.
To use it correctly, your model should allow a field to save html input from the user, but you want to "clean" it when it's used in the view so that unsafe or non-whitelisted tags/attributes is prevented from being sent/displayed to the user.
If you are looking to remove html tags/attributes before it gets saved, you may want to look at strip_tags.
strip_tags("Strip <i>these</i> tags!")
# => Strip these tags!
strip_tags("<b>Bold</b> no more! <a href='more.html'>See more here</a>...")
# => Bold no more! See more here...
strip_tags("<div id='top-bar'>Welcome to my website!</div>")
# => Welcome to my website!
Related
I'm looking to standardize all the buttons and button-styled elements in our Rails app with a button component. This means rendering a styled <button> element with type "button" or type "submit". I'm making use of the view_component gem provided by github!
I am hoping to be able to replace all Rails form helper-y elements such as button_tag, submit_tag and f.submit with a button element. I'm pretty new to Rails, and I am not sure if there are things happening under the hood I'm not taking into account. Looking at the Rails documentation, it doesn't seem like there anything special with the f.submit form helper element.
Am I missing something? Are there consequences to replacing rails form helper submits with a button[type='submit']?
It would be long way to change stuff, so Better to use css and adjust css to get your requirements.
Just add following in you code to create your own my_submit_button
### app/helpers/application_helper.rb ###
module ApplicationHelper
def my_submit
# decide what the submit text should be
text = if #record.new_record?
"Create #{#record.class}"
else
"Update #{#record.class}"
end
# build and return the tag string
my_submit_tag(text)
end
end
further you can read here
The form_for helper
I have some translations that I use in my views. These translations sometimes return very basic HTML markup in them -
t("some.translation")
#=> "This is a translation with some markup<br />"
(Side note: I'm using the fantastic it gem to easily embed markup, and specifically links, in my translations)
What if I wanted to strip the HTML tags in certain cases, like when I'm working with the translation string in my RSpec tests. Is there an HTML strp functionality that will compile and remove that markup?
t("some.translation").some_html_strip_method
#=> "This is a translation with some markup"
Thanks!
You may want to try strip_tags from ActionView::Helpers::SanitizeHelper
strip_tags("Strip <i>these</i> tags!")
# => Strip these tags!
strip_tags("<b>Bold</b> no more! <a href='more.html'>See more here</a>...")
# => Bold no more! See more here...
strip_tags("<div id='top-bar'>Welcome to my website!</div>")
# => Welcome to my website!
Depending on where you use it.
strip_tags method not functioning in controllers, models, or libs
It comes up with an error about white_list_sanitizer undefined in the class you’re using it in.
To get around this, use:
ActionController::Base.helpers.strip_tags('string')
To shorten this, add something like this in an initializer:
class String
def strip_tags
ActionController::Base.helpers.strip_tags(self)
end
end
Then call it with:
'string'.strip_tags
But if you only need to use it in VIEW, simply:
<%= strip_tags(t("some.translation")) %>
I have everything at the point where I'm about to send out the email but I need to modify all links to include Google Analytics attributes. The problem is that if I try and read/write the html_part.body of the email, the entire html string somehow becomes encoded and doesn't display the email properly (i.e. <html> becomes <html>). I have logged the html_part.body.raw_source in the logger and it shows as proper unencoded HTML, it's only when the email is actually sent does the encoding occur.
EBlast.rb (ActionMailer)
def main(m, args={})
# Parse content attachment references (they don't use helpers like the layout does)
# and modify HTML in other ways
m.prep_for_email self
#email = m # Needed for helper methods in view
mail_args = {
:to => #user.email,
:subject => m.subject,
:template_path => 'e_blast',
:template_name => 'no_template'
}
mail_args[:template_name] = 'main' if m.needs_template?
m.prep_for_sending mail(mail_args)
end
Email.rb
def prep_for_sending(mail_object)
if mail_object.html_part
# If I simply do a 'return mail_object', the email sends just fine...
# but the url trackers aren't applied.
# Replace the content with the entire generated html
self.content = mail_object.html_part.body.decoded
# Add Google analytics tracker info to links in content
apply_url_tracker :source => "Eblast Generator", :medium => :email
# Replace the html_part contents
mail_object.html_part.body = content
# At this point, mail_object.html_part.body contains the entire
# HTML string, unencoded. But when I send the email, it gets its
# entities converted and the email is screwed.
end
# Send off email
mail_object
end
Looks like I'm answering my own question again - I'm on a roll this week.
Apparently setting the body directly creates some odd attribute called 'body_raw' instead of replacing the raw_contents of the html_part. So basically I ended up having a duplicate part embedded in the mail object (I don't know why it does this). Creating a separate Mail::Part and assigning it to html_part just added another part instead of replacing html_part! WTF?!
New Edit: Scratch my last remark about String.replace. It looked like it was working but when I went to another computer and tested it, the same problem of duplication occurred.
Another Edit: Finally?
Before I executed the apply_url_tracker method I had reset the content of the email (for the purposes of changing all the links in the rendered view). I don't have any idea why that screws with the Mail object considering the message should already have been rendered but changing my methodology to the following has fixed the duplication of email parts and their subsequent 'reencoding'. I no longer change the content attribute, I only change the html_part:
def prep_for_sending(message)
if message.html_part
# Replace the html raw_source
message.html_part.body.raw_source.replace apply_url_tracker(message.html_part.body.decoded, :source => "Eblast Generator", :medium => :email)
end
message
end
Clarification:
Even though the call to mail() produces a Mail object with fully rendered HTML/Text parts (i.e., fully rendered views), changing the attribute that is USED by those views (in my case, the 'content' attribute) screws up the final send. Don't modify your model before sending, JUST MODIFY THE MAIL PART DIRECTLY.
Is there anyway to go up the DOM tree from the html_tag element passed in?
ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
# implementation
end
Is there anyway I can implement this method to move up the DOM tree and place a class on the parent div?
For example:
<div class="email">
<label for="user_email">Email Address</label>
<input id="user_email" name="user[email]" size="30" type="text" value="">
</div>
I would like to place a class on the div.email rather than place something directly on the input/label.
Can this be done with the field_error_proc method or is there a clean alternative?
I want to avoid doing this explicitly in my views on every form field. (like the following)
.email{:class => object.errors[:email].present? 'foo' : nil}
=form.label :email
=form.text_field :email
FYI: Short answer to my question is that there is no way to gain access to additional portions of the DOM in the field_error_proc method. This is due to the fact that these methods are not actually building a DOM but instead just concatting a bunch of strings together. For info on some possible work arounds, read the solutions below.
You have two options that I can think of off the top of my head:
Rewrite ActionView::Base.field_error_proc
In one situation I rewrote ActionView::Base.field_error_proc (there is a rails cast on it). Using a little nokogiri, I changed the proc to add the error messages to the input/textarea element's data-error attribute instead of wrapping them in an error div. Then a wrote a little javascript using jquery to wrap all inputs and their labels on document ready. If there was error information associated with the input/textarea, it is transferred to the wrapper div.
I know this solution relies on javascript, and may or may not have a graceful fall back, but it works fine in my situation since it is for a web app rather than a publicly accessible site. I feel okay requiring javascript in that scenario.
# place me inside your base controller class
ActionView::Base.field_error_proc = Proc.new do |html_tag, object|
html = Nokogiri::HTML::DocumentFragment.parse(html_tag)
html = html.at_css("input") || html.at_css("textarea")
unless html.nil?
css_class = html['class'] || ""
html['class'] = css_class.split.push("error").join(' ')
html['data-error'] = object.error_message.join(". ")
html_tag = html.to_s.html_safe
end
html_tag
end
Write a your own ActionView::Helpers::FormBuilder
You can also get more or less the same effect by overriding the text_field method so that it always returns a wrapped input. Then, using the object variable, access the errors hash and add any needed error information to the wrapper. This one does not require javascript and works nicely, but in the end I prefer the first approach because I find it more flexible. If however, I was working on a publicly accessible site, I would use this approach instead.
Also, FYI, I found it handy to override the check_box and radio_button methods so they always return the input with its associated label. There are lots of fun things you can do with a custom FormBuilder.
# place me inside your projects lib folder
class PrettyFormBuilder < ActionView::Helpers::FormBuilder
def check_box(field, label_text, options = {})
checkbox = super(field, options)
checkbox += label(field, label_text)
#template.content_tag(:div, checkbox, :class => "wrapper")
end
end
The above example shows how to wrap a check_box, but it is more or less the same with the text_field. Like I said, use the object.errors to access the errors hash if needed. This is just the tip of the ice berg... there is a ton you can do with custom FormBuilders.
If you go the custom form builder route, you may find it helpful to modify the above ActionView::Base.field_error_proc as follows so you don't get double wrapped fields when there are errors.
ActionView::Base.field_error_proc = Proc.new do |html_tag, object|
html_tag # return the html tag unmodified and unwrapped
end
To use the form builder either specify it in the form_for method call or place the following in your application helper:
# application helper
module ApplicationHelper
ActionView::Base.default_form_builder = PrettyFormBuilder
end
Often my solutions end up using some combination of each to achieve the desired result.
An embaressing question, but I can't seem to translate the documentation to an actual form_for. This is all the site provides..
RedCloth.new("Some text").to_html
#=> "<p>Some text</p>"
I get that that's how I parse it after its been saved. But how do I save it as marked up text?
Here's my attempt at beginning this, but I don't know how to set the parameter to save the textarea as RedCloth. Any ideas?
- form_for #text do |f|
# some RedCloth instantiation
f.submit
You don't save the parameter parsed as RedCloth like that, nor would I recommend it. Parsing it into RedCloth will result in the original value being lost unless you stored the output in an alternate field, which is what I would recommend.
You can use a before_save in your model to parse that value and store it:
before_save :parse_text
# your model methods go here
private
def parse_text
self.parsed_text = RedCloth.new(text).to_html
end
When you want to render the parsed_text value in your view you'll have to tell Rails that it's safe by doing this:
#object.parsed_text.html_safe
However, the code contained here does not account for people mixing Markdown and HTML, so be very careful how you use it.