Rails Tricks

Archive

23 Apr

Rails Tricks change of direction and The tale of an XSS in Phlex

You probably noticed that I haven't sent an email for a long time. The main reason for that is the articles I wrote recently doesn't really fit into the "Rails trick" category. But I believe they are still relevant to Rails developers, so I decided to change the newsletter format a little. The newsletter will be bi-weekly instead of weekly. It will still include one short article in the Ruby, Rails and security space. Besides that, if I write more than one article in that period, it will have links to those articles and if I came across anything I think is worth sharing, I might include that too with my thoughts on it.

This is the first such issue of the newsletter, so let's get into it.

Read more

30 Jan

The link_to helper in Rails

The link_to helper in Rails creates an anchor element with the given URL and options. Although the helper has a simple task, it can be used in quite a few ways, and in this article, I will try to cover most of them. Let’s start with creating a simple link:
link_to "Articles", articles_url
# <a href="/articles">Articles</a>

link_to @article.title, article_url(@article)
# <a href="/articles/1">This is my first article</a>
Now if you want, instead of the URL, you can specify URL params as the second parameter to achieve the same result:
link_to @article.title, controller: :articles, :action: :show, id: @article
# <a href="/articles/1">This is my first article</a>
Or to make it compact, you can just pass the object instead of the URL and Rails will infer the URL from the object:
link_to @article.title, @article
# <a href="/articles/1">This is my first article</a>
And since Rails 7, we can compact this even more and just pass an object to link_to. The name will be the result of the to_s method of the object, so in the above example, we override that method on our model:
# app/models/articles.rb
class Article < ApplicationRecord
  def to_s
    title
  end
end

link_to @article
# <a href="/articles/1">This is my first article</a>
There might be a situation when in place of the name, you want to display the whole URL you are linking to. To achieve this, you can pass nil as the first parameter:
link_to nil, "https://external_site.com/"
# <a href="https://external_site.com/">https://external_site.com/</a>
Now imagine that you want to have an icon in front of the name of the link. This helper makes adding that easy. If you call it with the URL and a block, it will use the result of the block for the name attribute:
link_to new_article_path do
  heroicons('plus-circle', class: 'mr-1') + "New article"
end
# <a href="/articles/new"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6 mr-1"><path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" /></svg>New article
</a>

I haven’t mentioned it yet, but the last parameter of the link_to helper is the HTML attributes, so if you want to style your link, you can pass the classes there:
link_to @article.title, @article, class: 'underline'
# <a href="/articles/1" class="underline">This is my first article</a>

Prior to Rails 7, you can pass in the Rails UJS Attributes in this HTML options hash too. So for instance if you want to have a link which does a post request, or uses the delete method, you could do this:
link_to 'Delete article', @article, class: 'underline', method: :delete
# <a href="/articles/1" class="underline" data-method="delete">This is my first article</a>
To ask for a confirmation, you can use the confirm option:
link_to 'Delete article', @article, class: 'underline', method: :delete, confirm: "Are you sure you want to delete '#{@article.title}'?"
# <a href="/articles/1" class="underline" data-method="delete" data-confirm="Are you sure you want to delete 'This is my first article'?">This is my first article</a>
And if you want the link to make an AJAX request, there is the remote option:
link_to 'Delete article', @article, class: 'underline', method: :delete, remote: true
# <a href="/articles/1" class="underline" data-method="delete" data-remote="true">This is my first article</a>

Rails UJS is deprecated since version 7, and Turbo is enabled by default, so instead of the above options, you can use the turbo_method and turbo_confirm options:
link_to 'Delete article', @article, class: 'underline', turbo_method: :delete, turbo_confirm: "Are you sure you want to delete '#{@article.title}'?"
# <a href="/articles/1" class="underline" data-turbo-method="delete" data-turbo-confirm="Are you sure you want to delete 'This is my first article'?">This is my first article</a>

Now consider the situation when you conditionally want to display a link. You can wrap the link_to call into a condition, but Rails has a link_to_if and a link_to_unless helper. I wrote about those helpers in an earlier post: https://greg.molnar.io/blog/rails-tricks-issue-1/

And if we are talking about link_to, there is an important security related information about the helper. The second parameter accepts a string for the href attribute of the a tag. The HTML specification permits various protocols for that attribute, including javascript, so for instance, you can make a dummy link with the following:
link_to "Click me", "javascript: void(0)"

Now let’s say in your application a user can specify the URL for their blog and you pass that to link_to:
link_to "Greg's Blog", @user.blog_url

This user can set the blog URL to javascript: XSS_PAYLOAD, and when someone clicks the link, the browser executes the JavaScript. To mitigate this issue, always validate the format of a URL your application accepts, especially if you intend to use it for linking to that URL.

That’s is for today, until next time!

19 Dec

Rails attribute changed callback

This week, I’d like to show you how to do an action, when an Active Record model’s attribute changes.
In the example, we have a User model, and we want to send an email to the user when the verified attributes changes to true.
As a first step, we need to add an after_save callback to the model:

Read more

21 Nov

Using thor for command line tasks

Last week, while creating a small Rails app for myself, I had to import data from an XML file. I wanted to add a command line task for it. I could’ve used rake for this, but I needed to input the path to the file through a command line parameter, and rake isn’t ideal for that. Fortunately, there’s another tool that’s better suited for this task: Thor.

Read more

14 Nov

Open redirect vulnerabilites in Rails apps - Rails Tricks Issue 22

Today, I want to tell you about open redirect vulnerabilities and how to prevent them in a Rails application.

Read more