Sanitize for all fields - ruby-on-rails-3

I'm looking for a proper way to sanitize all fields before saving results to database. There should be a way to do this, because user can add some html to any field in all user forms...
Thanks!

If by 'sanitize' you mean 'avoid SQL-injection attacks', ActiveRecord should be magically handling it for you. However, it sounds like you're talking about preventing users from being able to enter html in a form and have that html processed when the form's content is displayed.
Rails templates automatically escape html in templates. Thus, if foo = "<b>bar</b>", putting <%= foo %> in a Rails template will display the tags, not evaluate them. In order to force unescaped html, you would have to use the raw helper (<%= raw(foo) %> will not escape the tags).

Related

Redmine: Copy issue multiple times

Copying one issue and its child issues is a natively built-in feature and thus works just fine.
But is there a way to do this multiple times?
Like re-creating one issue (including its children) twenty or fifty times?
Edit 2
This new functionality should be accessible via the Redmine interface and compatible to any browser.
It does not matter whether it is a completely new Plugin, an extension to the built-in copy feature, a call to a PHP-script or anything else.
Due to compatibility (networking, browsers etc.) I guess a completely server-side modification is the only way to go here.
What parts of the default plugin (as created in the voting tutorial) or a core element would have to be changed?
Where can I find the code for the native issue copy function?
Or - if all this is too complicated - how would I write my plugin to point to a PHP file that manipulates the SQL database directly?
Edit:
To clarify: just like the normal copy function (either in the context menu or the top-right link, I don't care) I want to copy one issue and its sub-issues n times.
To let the user set the amount n, any user number input may suffice, like a textbox, a pop-up etc.
I think the simplest way to do this is to start with redmine source modification.
Once it works you can move on and try to extract this feature into plugin.
Note, that I am not a ruby developer, so some things below are just my guesses. But I did few small redmine modifications like this before and hope that my thoughts can be useful.
It will also be easier if you familiar with some of MVC frameworks (for any language), because they mostly have a similar structure with routes, controllers, views and models.
The Idea
The link to copy single issue looks like this: //redmine.myserver.com/projects/myapp/issues/12407/copy.
My idea is to add a num_copies parameter to this link and use it in the code to create many copies.
You need no UI for that, once implemented the feature will work like this:
find the issue you need
choose the copy action for it
once the form opened, manually add ?num_copies=XX parameter into the URL (//redmine.myserver.com/projects/myapp/issues/12407/copy?num_copies=50) and press 'Enter' to reload the form
check the details and submit the form - it will create multiple copies according to the num_copies parameter
The Implementation Plan
Now, how to do this.
I am referring to the redmine mirror on github which looks fresh.
1) Find where the .../copy link is handled
When you open the form to copy the issue, you'll see form like this:
<form action="/projects/myapp/issues" class="new_issue" id="issue-form" method="post">
<input id="copy_from" name="copy_from" type="hidden" value="12407">
<div class="box tabular">
<div id="all_attributes">
...
</form>
Note the form action, it points to the /issues link and it will submit the copy_from parameter (this is ID of the issue we are copying).
2) Find the code which handles the form submission
We could first go and check through the config/routes.rb, but we can just guess that we need the controllers/issues_controller.rb
Search for the place where copy_from parameter is used.
You'll see the build_new_issue_from_params method.
Now search for its usages and you'll find this:
before_filter :build_new_issue_from_params, :only => [:new, :create]
From how it looks, I guess that it is called before both new and create actions.
Looking at new and create definitions, the new action renders the new issue form and the create action handles the form post.
3) Add the num_copies parameter to the form
Find the view file used by new issue action.
Here there is a template for the new issue form, try to add num_copies parameter similar to the copy_from:
<%= title l(:label_issue_new) %>
<%= call_hook(:view_issues_new_top, {:issue => #issue}) %>
...
<%= error_messages_for 'issue' %>
<%= hidden_field_tag 'copy_from', params[:copy_from] if params[:copy_from] %>
Here I am not 100% sure if it will just work if you add a similar line for `num_copies. You may also need to modify the route.
When done, you should have the new issue form like this:
<form action="/projects/myapp/issues" class="new_issue" id="issue-form" method="post">
<input id="copy_from" name="copy_from" type="hidden" value="12407">
<input id="copy_from" name="num_copies" type="hidden" value="50">
<div class="box tabular">
<div id="all_attributes">
...
</form>
4) Handle the num_copies parameter
It should be done in the create action:
def create
...
call_hook(:controller_issues_new_before_save, { :params => params, :issue => #issue })
#issue.save_attachments(params[:attachments] || (params[:issue] && params[:issue][:uploads]))
if #issue.save
...
end
Here you already have the #issue variable created in the build_new_issue_from_params method and what you need to do is to check if num_copies parameter is set and if it is set then copy / save the #issue in a loop to create additional copies.
I can't provide the exact code snippet for this, but it should not be very complex.
Check this code in the bulk_update method, it looks like what you need:
issue = orig_issue.copy({},
:attachments => copy_attachments,
:subtasks => copy_subtasks,
:link => link_copy?(params[:link_copy])
)
I think this specific plugin is not high priority for Redmine community.
But, you can write very easy API calling for Java, Python or other language to do what you exactly want.
Here, you can see API documentation how to list, create, update issues.
Issue API documentation
PS: You can leave your request in redmine community,
maybe you are lucky https://redmine.org/projects/redmine/issues

Model paper clips validations errors are not displayed in simple_form

I am using paper_clip and simple_form gems. Unfortunately, it seems that paper clip validations errors are not displayed in my form.
I have try several types and syntax of paper_clip content_type validations and even they work (the uploaded files types are restricted) no error is displayed in the form.
Has anyone knew know how to fix this?
Here's what I suspect - the paperclip validation is likely being made on an attribute that's not actually an input in simple_form.
You might have something like this in your form:
<%= f.input :picture, :label => "Picture" %>
But paperclip's validation errors aren't going to be put on 'picture' - they'll be put on another attribute, like 'picture_file_name'. Since simple_form has a 'picture' input, and not a 'picture_file_name' input, it doesn't know where to put the errors, so they don't show up.
Take a look at your errors array and confirm what attribute's getting the errors. Then use simple_form's errors helper in your view to put that attribute's error in the appropriate place:
<%= f.error :picture_file_name %>
Unfortunately paperclip provides own format for validation errors storing them in 3 different attributes without linking to base model attribute:
*_file_name, *_file_size, *_content_type
Therefore simple_form or any other form view helper could not map paperclip validation errors with field name.
You can patch paperclip like described here http://dev.mensfeld.pl/2013/05/paperclip-bootstrap-and-simpleform-working-together-on-rails/ and forget about this issue forever

How do you edit Devise error messages?

To be clear, I know how to edit the error messages in config/locales/devise.en.yml but I'm referring to styling these type of error messages:
2 errors prohibited this user from being saved:
Email can't be blank
Password can't be blank
--
All i see is <%= devise_error_messages! %> on the sign-up page, but I don't know how to actually edit the error messages themselves.
In my case the messages appear on the left, and my sign up is centred (which looks odd), I also don't like the red color of the messages and would prefer a different color.
So my question is, how can I style the error message? centre it, and change the color.
Not sure which other controllers or contents to include so as soon as you ask, i'll update the OP with them if need be.
See the sources for the devise_error_messages! method at https://github.com/plataformatec/devise/blob/master/app/helpers/devise_helper.rb.
All the errors are inside
<div id="error_explanation">
so you can use that fact in your CSS. Inside it uses only basic styling: h2 for the header message, ul for the individual errors. See this SO example for #errorExplanation styling, for example: how to beautify validations in rails. Just don't forget to replace #errorExplanation with #error_explanation in the example.
But your best approach would probably still be to rewrite this method or write and use your own, and there apply all the styling you like.
I'd personally recommend displaying errors next to the fields they belong to. See this SO thread, for example, on how to do that: Rails: Errors close to particular fields in forms.
Another improvement would be switching to simple_form for your forms (and getting errors-next-to-fields for free). See, for example, an excellent Railscast on that: http://railscasts.com/episodes/234-simple-form. There's a more recent revised Railscast, but not sure if you're a Pro subscriber there.

Use JS to change <form> from remote to non-remote in Rails 3, HAML

The problem is that i have a remote form that, based on condition, id like to convert to a non-remote form (using UJS), and then submit.
note the form has a file upload.
Here's the details: I have initially rendered the remote form using
= form_for #myobj, :url => {:action=>"remoteAction", :controller=>"myobjects"}, :remote => true do |f|
... (f.fields....)
which produces the HTML:
<form id="new_myobj" class="new_myobj" method="post" accept-charset="UTF-8" data-remote="true" action="/remoteAction">
when i click submit, as expected, the form is submitted 'AS JS'.
in the controller action, i am doing some validation of the fields inside the submitted form.
If all the validations pass, i execute the following .js.haml template:
$('form#new_myobj').removeAttr("data-remote");
$('form#new_myobj').attr('enctype', 'multipart/form-data');
$('form#new_myobj').attr('action', '/myobjects/regularAction');
which successfully changes the HTML on the page (witnessed via Firebug) to:
<form id="new_myobj" class="new_myobj" method="post" accept-charset="UTF-8" enctype="multipart/form-data" action="/myobjects/regularAction">
since the form contains an f.file_field, i have to submit as multipart so the image can be uploaded, and i cannot submit 'AS JS'
now, when i click submit, the controller action 'regularAction' is indeed called, but its still 'AS JS'
the question is, what else do i need to change in the HTML so the form can be submitted non-xhr? is it related to the headers?
jQuery is a bit tricky with the data attributes since it both
reads the HTML5 data tags as well as its own storage bound to the
DOM element, that is also called data. When writing to an attribute
that value gets copied into jQuerys own data storage (presumably
when data("remote") is being called).
However, this only happens
if jQuery’s data is empty for that name. Thus setting the attribute will only work once, after that the "cached" value is being used
even if the attribute changes. In order to really get rid of the
value, we need to remove the attribute and jQuerys own storage
method in that order. The reason is that there’s a high-level
(element.removeData(…)) function and a low level one (jQuery.
removeData(element, …)). The former re-reads the HTML5 data
attribute and stores it in jQuery’s own storage. Using the rather
unusual low level function obviously works as well.
Also, we do really need to remove the attribute -- setting it to
false is not enough since Rails only checks if form.data('remote')
is not undefined (look for it in jquery_ujs.js).
TL;DR:
attr("data-remote") != data("remote")
These two lines make a form non-remote (again). Order matters.
$("form").removeAttr("data-remote");
$("form").removeData("remote");
It’s documented, if you actually know what you’re looking for:
http://api.jquery.com/jQuery.data/ (low level function)
http://blog.madebydna.com/all/code/2011/12/05/ajax-in-rails-3.html
StackOverflow doesn’t allow me to post more than two links, but you can guess the removeData one. The high-level functions are linked from the low level ones.
Avoiding the token authenticity error in Rails 4+:
As Stan commented below, just doing the above will fail with an InvalidAuthenticityToken error. The workaround is easy though, see here for details: https://stackoverflow.com/a/19858504/1684530
The problem is that your approach to disable the Ajax submission isn't quite correct. You need to unbind the JavaScript events that have already been added by rails.js (Rails UJS adapter) to the form.
You can do that by:
$('form#new_myobj').unbind() to unbind all events attached to the form. You also need to $('form#new_myobj').removeAttr('data-remote') and $('form#new_myobj').removeAttr('data-type') to remove data-remote and data-type attributes (if existent).

Rails 3 rendering iframe with raw()

So I am storing the whole embed code from youtube into my database and then outputting it like this.
<%= raw(people.video) %>
which outputs the general iframe tag copied from youtube:
<iframe src="foo" width=400 height=380></iframe>
the problem is that it actually displays that tag instead of embedding the video into the page itself. I can get around this just by storing the src in the database.... but this is part of a mini cms system and the site admins would find it much easier just to copy and past the embed code from youtube. Is there someway I can specify for the iframe to actually render instead of just spitting out the html on the page?
You can use the raw method to render the HTML of a string, are you storing it that way? You can also try the RedCloth gem - I was able to get this working like so:
<%= raw RedCloth.new(#page_content.content).to_html %>
Which allowed for my custom CMS to use the Textile markup
http://en.wikipedia.org/wiki/Textile_%28markup_language%29
I'm not 100% on what you're seeing, since raw should render HTML, but you might also try to include the embed tag using a JavaScript.write, since there are some issues related to Flash objects embedded in HTML vs JavaScript.
Let me know if this doesn't work, and if so, can you provide screenshots or copy what you're seeing on the page?