I've made a helper method that processes a tweet's body so that if there is any mentions a link will be added to it. It does do it, but when a username mentioned matches a part of a longer username (e.g #test #test2) only #test will be linked.
The resulting html looks like this:
#test #test2
How can I make it look like this:
#test #test2
This is my helper method:
def render_body(twit)
return twit.body unless twit.mentions.any?
processed_body = twit.body.to_s
twit.mentions.each do |mention|
processed_body = processed_body.gsub("##{mention.user.username}", "<a href='/user/#{mention.user.id}'>##{mention.user.username}</a>")
end
return processed_body.html_safe
end
I've checked the db and it does record the mention of #test2, it's just not able to render it.
A simple string substitution won't work here, you will have to use an anchored regex. This means that you never match parts of a word, only whole words:
processed_body = processed_body.gsub(/\b##{mention.user.username}\b/,
"<a href='/user/#{mention.user.id}'>##{mention.user.username}</a>")
Here we replaced the pattern string with a regex and used \b to anchor it to word boundaries.
I am developing a crypto-related application and since those people who deal in crypto will always try some sort of scam or script kiddie "hack" I'd like to figure out the best way to clean up content in user-to-user chat boxes and comments fields.
I don't want any HTML/CSS/JS in there.
I want to leave email addresses, URLs, phone numbers and "normal" text untouched.
Right now I am doing a .gsub(/[^0-9a-zA-Z\#\;\:\-\_\,\.\ ]/i, '') before_save but it removes the newlines.
I tried adding .gsub(/[^0-9a-zA-Z\R\#\;\:\-\_\,\.\ ]/i, '') to make it leave newlines alone but it does not seem to work.
Would prefer not having to add any gems.
Rails has an excellent sanitizer built in, that I would recommend you use instead of trying to figure out your own regular expressions.
See:
http://api.rubyonrails.org/classes/ActionView/Helpers/SanitizeHelper.html
Before you render any user's input out the page wrap it in santize
<%= sanitize #comment.body %>
If you want to sanitize before saving to the database, you can include the helper into your controller
class MyController < ApplicationController
include ActionView::Helpers::SanitizeHelper
def create
content = sanitize(params[:content])
Thing.save(content: content)
end
end
We have lots of templates that use a common paragraph of text (the description of our company services). The paragraph is currently duplicated among 10 different view templates.
Where should I create a variable like 'company_services_description' that I can use in all the different templates (to DRY it up).
Would defining it in application_controller.rb be the way to go?
Or perhaps would config/application.rb would be the right spot?
It depends how long the text it. I would suggest either storing the text in a partial and using it in your templates as follows:
<%= render "shared/company_services_description_partial" %>
or using an application helper method that you can call wherever you need it.
module ApplicationHelper
def company_services_description
"This is our company services description"
end
end
I'm trying to create an HTML string using a view. I would like to render this from a class that is not a controller. How can I use the rails rendering engine outside a controller? Similar to how ActionMailer does?
Thanks!
Rails 5 and 6 support this in a much more convenient manner that handles creating a request and whatnot behind the scenes:
rendered_string = ApplicationController.render(
template: 'users/show',
assigns: { user: #user }
)
This renders app/views/users/show.html.erb and sets the #user instance variable so you don't need to make any changes to your template. It automatically uses the layout specified in ApplicationController (application.html.erb by default). Full documentation can be found here.
The test shows a handful of additional options and approaches.
You can use ActionView::Base to achieve this.
view = ActionView::Base.new(ActionController::Base.view_paths, {})
view.render(file: 'template.html.erb')
The ActionView::Base initialize takes:
A context, representing the template search paths
An assigns hash, providing the variables for the template
If you would like to include helpers, you can use class_eval to include them:
view.class_eval do
include ApplicationHelper
# any other custom helpers can be included here
end
There is no need to over bloat your app with too many gems. As we know ERB is already included in your Rails app.
#jdf = JDF.new
#job = ERB.new(File.read(Rails.root + "app/views/entries/job.xml.erb"))
result = #job.result(binding)
Above there is snippet of code of an app I'm working on.
#jdf is a object to be evaluated in the erb view.
In my case I needed to render xml.
result is a string to be saved or sent anywhere you like.
In Rails 5:
view = ActionView::Base.new(ActionController::Base.view_paths)
view.render(file: 'template.html.erb')
In Rails 6.1:
lookup_context = ActionView::LookupContext.new(ActionController::Base.view_paths)
context = ActionView::Base.with_empty_template_cache.new(lookup_context, {}, nil)
renderer = ActionView::Renderer.new(lookup_context)
renderer.render(context, { file: 'app/views/template.html.erb' })
ActionView::Renderer.new() takes a lookup_context arg, and render() method takes a context, so we set those up first
ActionView::Base is the default ActiveView context, and must be initialized with with_empty_template_cache method, else render() will error
The {}, nil are required assigns and controller args, which used to default to {}, nil in Rails 5
Rails 6.1 requires a full filepath file: 'app/views/template.html', whereas Rails 5 only required the filename
"I'm trying to create an HTML string using a view." -- If you mean you're in the context of a view template, then just use a helper method or render a partial.
If you're in some other "Plain Old Ruby Object", then keep in mind you're free to use the ERB module directly:
erb = ERB.new("path/to/template")
result = erb.result(binding)
The trick is getting that 'binding' object that gives the context for the code in the template. ActionController and other Rails classes expose it for free, but I couldn't find a reference that explains where it comes from.
http://www.ruby-doc.org/stdlib-2.2.0/libdoc/erb/rdoc/ERB.html#method-i-result
Calling directly render method on ApplicationController may raise error
Helper Devise: could not find the `Warden::Proxy` instance on request environment
Instead we can use ApplicationController.renderer.render like
rendered_string = ApplicationController.renderer.render(
partial: 'users/show',
locals: { user: user }
)
Technically, ActionMailer is a subclass implementation of AbstractController::Base. If you want to implement this functionality on your own, you'll likely want to inherit from AbstractController::Base as well.
There is a good blog post here: https://www.amberbit.com/blog/2011/12/27/render-views-and-partials-outside-controllers-in-rails-3/ that explains the steps required.
For future reference, I ended up finding
this handy gem that makes this a breeze:
https://github.com/yappbox/render_anywhere
Best to render the view using a controller, as that's what they're for, and then convert it to a string, as that is your ultimate goal.
require 'open-uri'
html = open(url, &:read)
This time I've got problem with dividing text article into smaller parts. I don't need to figure out "automatic" algorithm based on words counting or something. All I need is something similar to function which is build-in Wordpress WYSIWYG editor (special breaking page tag).
I thought out only one solution so far. I don't want to divide specific article inside my database. I just want to place some tag inside article and divide it to array in show method.
Sample code:
#controller
#art = Article.find(:id)
if #art.value.contains?('<breaker>')
#parts = art.value.split('<breaker'>)
end
session[:current_part] = params[:current_part] ? params[:current_part] : #parts.first
...
render
#view
<%=h #parts[session[:current_part]] %>
How it sounds for you? It makes any sense? Cant wait for some advices.
It may be better to use an HTML comment so it does not affect the validation of the page.
In your Rails views, in the templates that show text before the breaker, you can split your content like what you have in the example code. I would perform this in a Rails helper module so it can be reused.
To view the full article, your helper method will return the full content if the parameter "more" is passed. The code may look something like this:
# controller
def show
#article = 'Before the break<!--more-->After the break'
end
# app/helpers/application_helper.rb
def show_more(article)
params[:more] ? article : article.split('<!--more-->').first
end
# show.html.erb
<%= show_more(#article) %>
It is generally good practice to keep the application logic in the model and helper files, and keep your controllers as simple as possible.