i have some model, let it be Post with field :content. Any user can submit post with html (with links of course:) ) and i'd like to set nofollow on those links. Is there any rails plugin to automate this task? Does this plugin have ability to manage "nofollowing" in conditional way - e.g. admin can add links without nofollow, but other - with only nofollow?
This should do what you're looking for: https://github.com/rgrove/sanitize/
Install the plugin, then for a block of text you can run:
<%=raw Sanitize.clean(#your_html, Sanitize::Config::BASIC) %>
There are other options that you can use to customise it, but the Config::BASIC version will detect all links in that block of text and add the nofollow tag to them.
You can define a helper for this, overriding (or rather wrapping) the default link_to
In app/helpers/posts_helper.rb do something along the lines of:
def nf_link_to(link_text, post)
opts = {}
opts[:rel] = "nofollow" unless post.author == "admin"
return link_to text, post, opts
end
So that in your view you can do:
<%= nf_link_to post.title, post %>
Which should result in:
My First[tm] Post
You should have a good look at the actual implementation of link_to and make your ''nf_link_to'' as complex as (as in; passing arguments and perhaps a block) as you desire.
Related
In my header page app.html.eex I have this link:
<%= gettext "English" %>
If a user is on any other path other than the root / , the user will be redirected to the root path, obviously because I send them there with ... Routes.page_path(#conn, :index ... .
So how can I form a link where it sends the user to the page he is on but with the parameter locale: "en" as I am processing this parameter in a browser plug and setting it as a language cookie and then return the user to the page the user was on.
Something like this:
<%= Routes.go(#conn.current_path, locale:"en")
The only way I know to make this happen requires you write the query string yourself (instead of passing a map, which is nicer). It looks like this:
<%= gettext "English" %>
This link will take you to the same page but you will only have the locale=en query params (any other ones will be gone). That, is you will only have %{"locale" => "en"} for your #conn.query_params.
If you want to investigate further yourself, you should try to understand the source code for the router helpers. It lives in $PROJECT/deps/phoenix/lib/phoenix/router/helpers.ex. I find this code very hard to understand. The unquote magic is new to me.
On my rails3 application I want to use redcarpet to handle user's posts and the user comment section. As such I'd like to extend redcarpet to support turning #username into a link to a user on my site. I know redcarpet is written in C but is there anyway easy way to extend it in ruby? How hard would it be to write it in C? Should I just do this outside of redcarpet?
Also I'm intrested in some other extensions of redcarpet that would be shorthand for linking to other models in my app. I'm not sure the syntax yet but I'm guessing it would be similar to how github handles linking to issues.
I found it pretty easy to extend redcarpet's parser in Ruby for my rails 3 app. It wasn't scary at all.
First, start by deriving a class from Redcarpet's HTML renderer and override the preprocess method as recommended in the docs. In Rails 3.2 and Rails 4, this file can go anywhere and you don't need to require it. I use a 'services' folder to hold code like this.
# app/services/my_flavored_markdown.rb
class MyFlavoredMarkdown < Redcarpet::Render::HTML
def preprocess(text)
text
end
end
Next step is to add methods that do text substitutions you want. Here I use regex to wrap text that looks like "#mention" in an HTML span tag with a css class 'mention'.
# app/services/my_flavored_markdown.rb
class MyFlavoredMarkdown < Redcarpet::Render::HTML
def preprocess(text)
wrap_mentions(text)
end
def wrap_mentions(text)
text.gsub! /(^|\s)(#\w+)/ do
"#{$1}<span class='mention'>#{$2}</span>"
end
text
end
end
You could just as easily look up a user's profile page and wrap the #mention in an anchor tag instead. In my case, I also made methods for emoticons and hashtags that worked the same way and chained the methods together.
The last step is to add a helper that accepts some text, creates an instance of your Redcarpet-derived class, passes the text into that for processing, and returns the html result.
# app/helpers/application_helper.rb
def flavored_markdown_to_html(text)
renderer = MyFlavoredMarkdown.new()
# These options might be helpful but are not required
options = {
safe_links_only: true,
no_intra_emphasis: true,
autolink: true
}
Redcarpet::Markdown.new(renderer, options).render(text)
}
In your views you can call it like this:
<%= flavored_markdown_to_html("This is something worth #mentioning") %>
The output would then be:
This is something worth <span class='mention'>#mentioning</span>.
I once tried to extend redcarpet, but found it very difficult. If there are no other dependencies on redcarpet I'd recommend you try rpeg-markdown which is a (somewhat outdated) Ruby gem providing bindings to the excellent peg-markdown.
peg-markdown is a markdown interpreter written as a formal grammar. This means that it is very easy to extend it with own syntax. I've successfully extended peg-markdown for my own projects (see my fork here) and I found it to be much simpler than fiddling with redcarpet's custom parser code.
I also found peg-markdown to have fewer bugs.
The Ruby bindings may have to be made current by updating the git submodule. (I'm planning to submit a pull request to update rpeg-markdown to the latest version of peg-markdown.)
I am currently working through Michael Hartl's Rails Tutorial while experimenting with some other things not covered in the book. After completing Chapter 5, where the static pages are created, I decided change the view code to HAML, internationalize the pages, and put the static content into separate (non-partial) Markdown files, using the RDiscount gem to render them. For example:
app/views/static_pages/about.html.haml
- provide(:title, t('.about_us'))
:markdown
#{render file: "static_pages/about.#{params[:locale]}.md"}
Under the static_pages directory, I have Markdown files like about.en.md, about.it.md, about.ja.md etc, so interpolating in the :locale parameter is what determines which language Markdown file gets rendered.
My questions are:
The static_pages directory is a bit crowded with Markdown files, so are there any sensible default/best practice locations (perhaps outside of the app directory) to keep these Markdown files, where they could be presumably be edited by people who don't need to know about the inner workings of the app?
What better ways are there to implement rendering multi-lingual Markdown files in views? My use of :locale and the double string-interpolation seems inelegant.
Is there a way to change this code so that I can pass Ruby variables into the Markdown file? I know I can, for example, use a #{language} variable in the Markdown by just changing about.en.md into a HAML partial (_about.en.html.haml) and change the code to look something like:
app/views/static_pages/about.html.haml
- provide(:title, t('.about_us'))
:markdown
#{render "about.#{params[:locale]}", language: 'Markdown!'}
But, is there a way to do this without changing the Markdown file into another type of file? If such a way exists, is it recommended/feasible?
After having a look at this StackOverflow answer, it seemed that the best location for i18n Markdown files would be their own action name directories under the config/locales directory, and that there was a good opportunity to refactor the render code on all views for the StaticPagesController. So, using about.html.haml as an example below, the call to render in the home, help, about, and contact views has been changed to the exact same code:
app/views/static_pages/about.html.haml
- provide(:title, t('.about_us'))
:markdown
#{render file: localized_page_for(action_name, params[:locale])}
The localized_page_for method is defined in the StaticPagesHelper:
app/helpers/static_pages_helper.rb
module StaticPagesHelper
def localized_page_for(action, locale)
"#{Rails.root}/config/locales/#{action}/#{action}.#{locale.to_s}.md"
end
end
So, now all the Markdown files have been taken out of the app/views/static_pages directory and are called from their respective logical directories (eg. config/locales/about/about.en.md etc) using ActionController's action_name attribute and the locale, making for less clutter.
As for question 2 above, string-interpolation seems to be common enough for this kind of problem, so I'll consider it "elegant" enough as well.
As for question 3 above, after exhaustive searching, I haven't found a way anyone has passed in variables in to a pure Markdown file, and the documentation doesn't seem to say anything about supporting them, so I'm going to conclude that it's not possible. If passing Ruby variables in to Markdown is absolutely necessary, the file will need to be run through another interpreter, kind of like is described in this StackOverflow answer.
Update:
After running security scanner Brakeman against the app, it came up with a potential Dynamic Render Path security warning (albeit a weak one) due to dynamically passing in params[:locale] to the render call instead of passing it a static string. So, I moved the call to the localized_page method out of the views, moved the method itself out of the StaticPagesHelper (so that file is now empty) and in to the StaticPagesController and then instantiated a #page instance variable in each method to pass to the view. In summary, the code now looks like this, which doesn't get the security warning:
app/controllers/static_pages_controller.rb
class StaticPagesController < ApplicationController
before_filter :localized_page, only: [:help, :about, :contact]
def home
if signed_in?
#micropost = current_user.microposts.build
#feed_items = current_user.feed.paginate(page: params[:page])
else
localized_page
end
end
def help
end
def about
end
def contact
end
private
def localized_page
#page = "#{Rails.root}/config/locales/"\
"#{action_name}/#{action_name}.#{params[:locale].to_s}.md"
end
end
app/views/static_pages/about.html.haml
- provide(:title, t('.about_us'))
:markdown
#{render file: #page}
I'm creating a site using a small Ruby framework, Sinatra, but I would like to be able to do something like what the Rails link_to_unless_current method does, without using Rails.
Now I have my own link_to method, which works the same as the Rails one, more or less, so how would I go about doing the _unless_current part?
Seeing as how you mentioned your link_to method is similar to the Rails one, give this a try:
def link_to_unless_current(text, location)
if request.path_info == location
text
else
link_to text, location
end
end
I gave this a quick test and worked perfectly for me, however if your link_to method takes more parameters, it's pretty simple to add more, just add them to the _unless_current(text, location, param1, param2, etc) and the link_to text, location, param1, param2, etc parts of the code.
Im working with Rails 3.0.9 and Ruby 1.9.2.
I have a search page that will display a list of results in grid format. However, I want to be able to give the user an option to display them in list format.
Could anyone please advise me about how I can offer a change view option,and still keep the search results?
As you have not specified where query is stored,
I will hope that in url, like example.com/search?query=mylookupstring
So in this case all we need is to place somewhere on a page, link_to search path and pass your query + some parameter back to controller to prepare new view
<%= link_to "List", search_some_thing_path(:query=>params[:query],:list=>true) %>
nice & easy
Post your details if i show bad skills with telepathy today.
UPDATE:
Pay attention to params & url. Yours & my example. You shouldn't just copy
as your controller expects params[:search] not params[:query]
So fix error in you link_to & move_on!
PS Great tip to find out how rails really work is to use debugger.
You may attach it in view
<% debugger %> or in model/controller simply debugger
Don't forget to include debug gems in your Gemfile, smth like
group :development, :test do
gem 'ruby-debug19'
end