ID from Controller#show - ruby-on-rails

I would like to retrieve the id of the current item in a Controller#show page. How is this done? I can't seem to figure this out or find it anywhere.

You're probably looking for:
<%= params[:id] %>
There are lots of things wrong with doing this, one of which is it can open you up to CSRF attacks. Make sure to escape your output (this is done automatically in rails 3.)

Related

In Rails, can I lookup a relation without explicitly looking it up in the controller?

I’m using Rails 4.2.5. In my model, my user has an attribute, “avatar_file_id” which links to a table in which the filename is defined. The “avatar_files” table has the fields
id
file
When the user is logged in, I want to display the avatar image on my page, but I’m having trouble figuring out how. In my controller, I have a reference to the logged in user (#current_user), and so I have
<%= image_tag "avatar_images/#{current_user.avatar_file_id}", alt: current_user.name %>
but clearly, this will only attempt to lookup a file where the filename is the id, which is not how things are setup. Do I need to explictly lookup the image file in my controller and then include that variable on the page or is there some slicker way of getting the image path given only the user object?
Thanks, - Dave
You can do something like
<%= image_tag "avatar_images/#{Avatar.find(current_user.avatar_file_id).file}", alt: current_user.name %>
But you skip a lot of safeguards to do it this way (i.e. what if a user hasn't uploaded an avatar image?) and if you put that sort of stuff in your view things really start to get messy.
Generally you want as little logic in your views as possible since it's much harder debug html/Ruby than the pure Ruby in your controller so it's probably better just to load the object in your controller and pass it through in a variable.

Why is my view being flagged as an XSS vulnerability?

I have a show route that displays the contents of my article
Controller:
def show
#article = Article.find(params[:id])
end
View:
...
<li class="content"><%= #article.content.html_safe %></li>
...
When running Brakeman, it flags the above as a potential Cross-Site Scripting (XSS) vulnerability
Unescaped model attribute near line 34: Article.find(params[:article_id]).content
I'm trying to figure out what XSS really is and what makes this vulnerable? If someone injected some malicious text or input into the params[:id] field in the route (e.g. /articles/BAD_INPUT) then Article.find() would not find the article and raise an error
The only way the view renders is if a valid Article record is found, right? How else can the user manipulate this?
Thanks!
Edit: I should definitely protect agains the case when an Article is not found and an error is raised, but I figured that's more of a bad design rather than a security vulnerability
Brakeman is warning because the code is taking information from the database and outputting it in a view without escaping it. By default, Brakeman treats values from the database as potentially dangerous. In this case, you probably know the article content is intended to be HTML and is safe to output without escaping it. If you wish to not warn about XSS with values from the database, you can use the --ignore-model-output option.
(The issue you linked in your answer is not really related. Brakeman is expected to warn about uses of raw/html_safe with potentially dangerous values.)
Ok found the answer after some digging.
It apparently has to do with html_safe and raw (which is just an alias for html_safe). The issue is specific to Brakeman and outlined here
That thread says the issue is acknowledged and solved, but it still didn't work for me using the latest version.
I solved it as follows
Controller:
def show
#article = Article.find(params[:id])
#article_content = view_context.raw(#article.content)
end
View:
...
<li class="content"><%= #article_content %></li>
...
Essentially we're marking the Article content as html_safe (using the alias raw()) beforehand so it doesn't cause an issue in the view.
Messier than I'd like, but it works
If you are storing html on your model and you are on Rails 4.2++, you could consider using the sanitize helper (docs).
For example, you can allow specific tags (e.g. links):
<%= sanitize #article.content, tags: %w(a), attributes: %w(href) %>
The docs have a lot of good examples.
Here's another write-up if you want some more information.

query strings are persisting across all controllers in error

I have a rails 3 application where I am passing some string queries like this:
<%= link_to "All", work_orders_path(params.merge({:status_filter => "E", :sort_filter => params[:sort_filter]})) %>
Everything works persistence wise in my views for work_order which is what these parameters are intended for (sorting and filtering existing work orders.)
The problem that I'm having is that when I go to add a new work order with a link_to, or attempt a link_to to another controller, the :status_filter and :sort_filter both are persisting, causing a routing error.
For example when I want to hit the index to view all technicians (of which these are not applicable I get
No route matches {:sort_filter=>nil, :status_filter=>"E",
:controller=>"technicians"}
I've looked everywhere for a solution but as of yet I've been unable to come up with anything. I've tried params.delete, no dice. I know there must be an easy way to clear these from the URL in the link_to but I can't figure it out.
I figured out that these links for all my navigation are in my application.html.erb, so any params I use there are carried across the entire app. I still haven't figured out why. I moved these links to the index.html.erb file in work_orders and now everything else works.

Rails user authorization

I am currently building a Rails app, and trying to figure out the best way to authenticate that a user owns whatever data object they are trying to edit.
I already have an authentication system in place (restful-authentication), and I'm using a simple before_filter to make sure a user is logged in before they can reach certain areas of the website.
However, I'm not sure the best way to handle a user trying to edit a specific piece of data - for example lets say users on my site can own Books, and they can edit the properties of the book (title, author, pages, etc), but they should only be able to do this for Books that -they- own.
In my 'edit' method on the books controller I would have a find that only retrieved books owned by the current_user. However, if another user knew the id of the book, they could type in http://website.com/book/7/edit , and the controller would verify that they are logged in, then show the edit page for that book (seems to bypass the controller).
What is the best way to handle this? Is it more of a Rails convention routing issue that I don't understand (being able to go straight to the edit page), or should I be adding in a before_find, before_save, before_update, after_find etc callbacks to my model?
check out the following gems:
cancan
devise
authlogic
and don't miss Ryan's great railscasts on the above
this will give access to anyone who changes the value in the address bar
#book = Book.find(params[:id])
but if you go through the association of the logged on user rails (ActiveRecord) will automatically update the sql query
#book = current_user.books.find(params[:id])
of course this assumes that your books table has a user_id column
You may need an authorization plugin. I had some experience use this plugin a while back. This article also has an overview:
You might also take a look at Declarative Authorization
Hey I have recently done this myself. The easiest way to do this is to have the edit feature display on the page but incase it in a method such as the following:
<%if current_user %>
<% if current_user.id == wishlist.user_id %>
<div id="text3"><%= link_to 'Edit', edit_wishlist_path(#wishlist) %></div><br />
<%end%>
<%end%>
Is this what you were hoping for?

Rails form protection questions, hidden field

I have a live rails website and I want to have a form with a lot of fields on it. I have set up validations and allowed formatting for every field. I've tested it quite a bit and it seems to catch anything I throw at it.
I think it's almost ready to go live, but I want to quadruple check if there's anything else I should do to protect it. My site has a low volume of visitors, but I want it to be a safe as possible. I'd like to avoid using a captcha if I can. I've read that you can use a hidden field to protect forms against bots.
Do people recommend this instead of using a captcha, or even using it with a captcha?
my form is really standard:
<% form_for(#entry) do |f| %>
...
<%= f.submit 'Create' %>
<% end %>
Any suggestions or code samples would be greatly appreciated.
You should whitelist a list of attributes that the user is allowed to edit in your model using attr_accessible
Write tests/specs for your models/controllers/views?

Resources