rails user input with <script>, stored, and displayed - ruby-on-rails-3

I have an application that collect user input and store to DB and show back to user.
One user entered "alert(1)" into the name field and saved it into DB.
Whenever the name is displayed, the page will be broken.
I know how to fix that input only with validation for input, and h() for output.
However, I have so many input fields and so many outputs that accept users' text.
Is there any simple way to prevent this happening(i.e. overriding params method, etc)?
I also want to know how you expert guys are dealing with this problem?

As of Rails 3, my understanding was that embedded ruby code was html escaped by default. You don't need to use h() to make it that way. That is, if you use <%= "<script>a=1/0;</script>" %> in a view, the string is going to be made html safe, and so the script doesn't execute. You would have to specifically use raw() or something similar to avoid it - which you should naturally not do unless you're really confident about the contents.

For output, Rails 3 automatically html-encode all text unless I use raw() method.
For input, How about making a common validator and apply to all fields that are text or string? Is it desirable?
http://api.rubyonrails.org/classes/ActiveModel/Validator.html
class MyValidator < ActiveModel::Validator
def validate(record)
record.class.columns.each do |c|
if c.type==:text || c.type == :string
record.errors.add c.type, "script tag is not allowed" if c[/<script[^>]*>/]
end
end
end
end

Related

rails form fields_for serialize hash

I need to create a check list for a comment form on which users to notify about a comment.
I have a comment model and i have a column called comment_meta which i want to store as a serialize hash.
My comment form has a fields_for comment_meta example;
<%= f.fields_for :comment_meta do |comment_form| %>
<%= comment_form.check_box(contact.id) %>
<% end %>
The params being passed are "comment_meta"=>{"155"=>"0", "156"=>"1", "157"=>"0"}},
but my db is saving an empty hash.
The field type for comment_meta is a text.
Is there a way to save this?
Your comment_meta hash seems to be a 'key-value pair' of ids and Boolean values, respectively. If this is true, then you may be better off going with a users_comment_metas 'through' table.
You would benefit from restructuring to this methodology because:
db indexing is fast - rails hash serialization/parsing to and from the db is slow (unless your using postgres's h-store, but thats another story)
Dynamic reporting about all data in your db will be much more intuitive/query-able as a developer attempting to display readable reports (which is very important at my job at least).
Your goal of using Rails' built in form helpers will be much easier.
If you truly want to go the hash route you've suggested, there could be a variety of things preventing it from saving. Here's how I would troubleshoot:
First make sure you have the line 'serialize comment_meta, Hash' in your Comment model.
Remove ALL validations you may have in the Comment model for testing purposes.
Now, type 'debugger' (no quotes) in your controller create and/or update
action in your comments_controller (or the controller you are
requesting from the form)
when you hit your debugger statement in your terminal, type the words
'eval comment_params' to check the comment params you've submitted (I am assuming you are using the strong parameters gem, seeing as you typed 'ruby-on-rails-4' in your tags for this post).
The hash should have this structure as you've suggested above (if it looks different,
something is wrong in your form, or you have strong paramters set up incorrectly, more info here):
"comment_meta"=>{"155"=>"0", "156"=>"1", "157"=>"0"}
type 'n' until you've passed the line initializing a new object with the params
#comment = Comment.new(comment_params)
Now type 'eval #comment' to see your new object, and then type 'eval #comment.comment_meta' to see if the hash is being stored. If it's returning nil, then type 'eval #comment.valid?'. If it returns true, then type #comment.errors to see what is wrong, and fix accordingly.
If all else fails, make sure you can do a manual assignment of any given hash to comment_meta of a new Comment object in your rails console:
#comment = Comment.new()
#comment.comment_meta = {"test"=>"1"}
#comment.save!
I hope this gets you on the right track.

uninitialized constant CallsHelper::Active

I'm writing a helper in my Calls view that changes the text of a span depending on a evaluation of a date. When I write the if/else in the view I can make it work but I get the error "uninitialized constant CallsHelper::Active" when trying to access it from my helper.
view code:
<%= status_indicator(call)%>
helper code:
def status_indicator(call)
if call.transfer_date > Time.zone.now
Scheduled
else
Active
end
end
I'm not sure what the error is trying to tell me besides it's not working. Can someone give me a hand and let me know where I'm going wrong?
I want to return strings and not Ruby classes. Putting "" around the strings fixed the problem.

What's a good way to insert a resource id into the params of another resource?

I'm really new to programming, so I'm having trouble explaining this -- please forgive.
I have a Document model and a Note model in my rails app. A note belongs to a document, and a document has many notes -- the foreign key in the notes table is document_id.
On my document show page, I have a form for a note which uses a :content attribute as a text_area field.
What I'd like to do is pass the document's id into the note params so the note would have both the :content the user submits alng with the :document_id based on the document_path.
Currently I'm adding the :document_id into the note's params hash using a hidden_field form helper, and sending the whole thing to the NotesController, but I hope there's a cleaner / perhaps easier way.
If this makes sense, can someone suggest a better way to do this? Thank you.
In your routes have something like
resources :documents do
resources :notes
end
Then you should be adding a note via this route
/documents/5/notes/new
Then in your NotesController have
def create
#document = Document.find(params[:document_id])
#note = #document.notes.build(params[:note])
if #note.save
# Blah
else
# Blah
end
end
(In no way has this been tested - but it gives you an idea of how to do it in a RESTFUL style without hidden fields)

Rails 3 Custom Validation against DB-Entries

I have currently a website which lets every user register, but I want to give out codes, so that only users with a special code can register. I already worked with validation, but I really need your help for doing this.
At first, I have my form which lets the user register and where the user can input the code.
Then I have the User Model, which should containt the validation checks:
validates :registration_codes, :presence => true, ??? => ???
I can get my reg_codes in any form, because I haven't created them yet. Maybe I will just update them manually and hardcode or maybe I will make a model. I don't know. So, what I just need is the validation check which should do something like this:
:registration_code should be code1 or code2 or code3
I have even tried to make a custom method, but I didn't find out how to forward the form input to my method.
Thanks for any help!
I wrote an custom method, which I call by:
validate :validate_regcode
And then I just search in the DB for the code and check if the result is empty:
def validate_regcode
regcode_feed = Code.where("regcode = ?", regcode)
if regcode_feed.empty?
errors.add(:regcode, "Ihr Registrierungscode ist leider ungültig.")
end
end
So, at all, it's really simple if you know the way to do it. Maybe there's something even simpler, but I like my way :)

Can you remove the _snowman in Rails 3?

I'm building an app on Rails 3 RC. I understand the point behind the _snowman param (http://railssnowman.info/)...however, I have a search form which makes a GET request to the index. Therefore, submitting the form is creating the following query string:
?_snowman=☃&search=Box
I don't know that supporting UTF encoding is as important as a clean query string for this particular form. (Perhaps I'm just too much of a perfectionist...hehe) Is there some way to remove the _snowman param for just this form? I'd rather not convert the form to a POST request to hide the snowman, but I'd also prefer it not be in my query string. Any thoughts?
You can avoid the snowman (now a checkmark) in Rails 3 by.... not using Rails for the search form. Instead of using form_tag, write your own as outlined in:
Rails 3 UTF-8 query string showing up in URL?
Rails helpers are great unless they're not helping. Do-it-yourself is good as long as you understand the consequences, and are willing to maintain it in the future.
I believe the snowman has to be sent over the wire to ensure your data is being encoded properly, which means you can't really remove the snowman input from forms. Since, it's being sent in your GET request, it will have to be appended to the URL.
I suppose you could write some javascript to clean up the URL once the search page loads, or you could setup a redirect to the equivalent URL minus the snowman. Both options don't really feel right to me.
Also, it doesn't seem there is any way to configure Rails to not output it. If you really wanted to get rid of it, you could comment out those lines in Rails' source (the committed patches at the bottom of railssnowman.info should lead you to the files and line numbers). This adds some maintenance chores for you when you upgrade Rails. Perhaps you can submit a patch to be able to turn this off?
EDIT: Looks like they just switched it to what looks like a checkmark instead of a snowman.
EDIT: Oops, back to a snowman.
In Rails 4.1 you can use the option :enforce_utf8 => false to disable utf8 input tag.
However I want to use this in Rails 3, so I monkey-patched my Rails. I put the following in the config/initializers directory.
# allow removing utf8 using enforce_utf8, remove after Rails 4.1
module ActionView
module Helpers
module FormTagHelper
def extra_tags_for_form(html_options)
authenticity_token = html_options.delete("authenticity_token")
method = html_options.delete("method").to_s
method_tag = case method
when /^get$/i # must be case-insensitive, but can't use downcase as might be nil
html_options["method"] = "get"
''
when /^post$/i, "", nil
html_options["method"] = "post"
token_tag(authenticity_token)
else
html_options["method"] = "post"
tag(:input, :type => "hidden", :name => "_method", :value => method) + token_tag(authenticity_token)
end
enforce_utf8 = html_options.delete("enforce_utf8") { true }
tags = (enforce_utf8 ? utf8_enforcer_tag : ''.html_safe) << method_tag
content_tag(:div, tags, :style => 'margin:0;padding:0;display:inline')
end
end
end
end