Retrieving YAML from a text field - ruby-on-rails

The serialize method allows an object like a hash to be stored in the database as a YAML string. However, I recently found myself wanting to have a text field to allow a user to input their own string and have the controller create a hash off of that string.
<%= f.text_field :yaml, :value => '--- \nlast_name: Smith\nfirst_name: Joe\n' %>
Yes, I want single quotes: I want to preserve the \n in the display. But the problem is that, as a result, the resultant string object gets escaped:
--- \\nlast_name: Smith\\nfirst_name: Joe\\n
I run the string through two regexes: The first replaces the double backslash with a single backslash. Then next converts \n (two characters) into \n (special single character).
So in my controller:
yhash = YAML.load(params[:form][:yaml].gsub(/\\\\/, "\\").gsub(/\\n/, "\n"))
This now works, but seems awfully convoluted. Is there a more elegant way for a user to submit yaml?

Are you saying you want the users to be able to write \n to mark the newlines in the yaml they are entering? Because in that case the way you are doing it now with regexps is very straightforward.
The escape sequence \n is a feature of Ruby strings. If you want to implement it in your web form yaml interface too, a regexp is a valid way to do that.
Are you sure you have to do the double-slash replacement? I think it should only show up as double-slash if you do .inspect.

Related

passing a column name as a variable to an ActiveRecord query

Let's say I have a query:
Foo.where("lower(bar) LIKE ?", "%#{baz}%")
which transforms to plain SQL as:
... WHERE (lower(bar) LIKE ...
and works perfectly. But instead of bar I want to pass an argument. So I tried to rewrite it like this:
Foo.where("lower(?) LIKE ?", bar, "%#{baz}%")
where bar is a variable containing a string 'bar'. In this case it stops working and transforms to plain SQL as:
... WHERE (lower('bar') LIKE ...
So how can I make this query work?
You might want to try using sprintf-style % escapes in the template to avoid the the column name you wish to interpolate from being quoted:
Foo.where("lower(%s) LIKE '%s'", bar, "%#{baz}%")
(N.B. The single quotes around the second %s - the second argument does want to be quoted)
Reference:
Lastly, you can use sprintf-style % escapes in the template. This works slightly differently than the previous methods; you are responsible for ensuring that the values in the template are properly quoted. The values are passed to the connector for quoting, but the caller is responsible for ensuring they are enclosed in quotes in the resulting SQL. After quoting, the values are inserted using the same escapes as the Ruby core method Kernel::sprintf.
You can construct your query via Arel:
bar = :field_name # or 'string_name'.to_sym
Foo.where(Foo.arel_table[bar].lower.matches("%#{baz}%"))

RAILS: Word_wrap for a long line of text across multiple lines

I am trying to use word wrap such that it can wrap a single long string of text within an array on multiple lines.
I found the link below to be somewhat helpful:
http://apidock.com/rails/ActionView/Helpers/TextHelper/word_wrap
I copied the regex listed in the link above, which matches a single long string within an array:
def breaking_wrap_wrap(msg, col = 80)
msg.gsub(/(.{1,#{col}})( +|$\n?)|(.{1,#{col}})/,"\\1\\3\n")
end
However, I'm not sure how to fix the regex to match the string within the array:
undefined method `gsub' for ["adsgagsdgds"]:Array
I couldn't get it to work in Rubular or another gsub testing tool, so was wondering if anyone knew how to match the array above and break the line if a single string in the array is greater than 80 characters?
Thanks!

Stripping commas from Integers or decimals in rails

Is there a gsub equivalent for integers or decimals? Should gsub work with integers? Basically I'm just trying to enter decimal into a ruby form and what the user to be able to use commas. For example, I want the user to be able to enter 1,000.99.
I've tried using
before_save :strip_commas
def strip_commas
self.number = self.number.gsub(",", "")
end
but get the following error "undefined method `gsub' for 8:Fixnum" where "8" is replaced with whatever number the user enters.
If your field is a Fixnum, it will never have commas, as Rails will have to convert the user input into a number in order to store it there.
However, it will do that by calling to_i on the input string, which is not what you want.
overriding the normal setter to something like
def price=(num)
num.gsub!(',','') if num.is_a?(String)
self[:price] = num.to_i
end
Not tested, but something resembling this should work...
You need to get at the commas while the input is still a string.
Edit:
As noted in comments, if you want to accept decimals, and create something not an integer, you need a different conversion than String.to_i. Also, different countries have different conventions for numeric punctuation, so this isn't a complete solution.
try self.number.gsub(/\D/, ''). That is, remove everything that isn't a digit. Regexen make no distinction between integers, floats, decimals, etc. It's all strings. And Rails won't convert it correctly for you, because it just calls #to_i or #to_f on it.
EDIT:
actually: self.number.gsub(/[^\d\.]/, '').to_f: everything that isn't a digit or decimal point, and convert it to a float.

Escape Comma values in fastercsv

I am working on the csv generation. I am seperating values which are seperated by comma(,). If the value in a field contains comma, then it should not seperate the field in excel. So I want to put a escape character there. I am using FasterCsv. So how I can put a escape character. What is the escape character of fastercsv?
Just quote every field (doublequotes by default) and commas inside of them are ignored:
CSV.generate(:col_sep=>',', :quote_char => '"') do |row|
row << ["Quid, quid", "latinum dictum"]
row << ["sit, altum", "viditur."]
end
=> "\"Quid, quid\",latinum dictum\n\"sit, altum\",viditur.\n"
If you have commas in your data, set a different column seperator with the :col_sep option. If you like your commas and can not live without them, set the data within quotation marks.
If you use the FasterCSV methods, this will be handled for you automatically!
a creative way is to replace the real comma with a look-alike. This may be stupid, it all depends on your use case. It was ok for us - I think. I need to post this before I change my mind, lol
my_string.gsub(',','‚')
I'm not sure if it copy pasted this correctly, but you can create it on mac by holding ALT(option) + ,

Rails validates_format_of

I want to use validates_format_of to validate a comma separated string with only letters (small and caps), and numbers.
So.
example1, example2, 22example44, ex24
not:
^&*, <> , asfasfsdafas<#%$#
Basically I want to have users enter comma separated words(incl numbers) without special characters.
I'll use it to validate tags from acts_as_taggable_on. (i don't want to be a valid tag for example.
Thanks in advance.
You can always test out regular expressions at rubular, you would find that both tiftiks and Tims regular expressions work albeit with some strange edge cases with whitespace.
Tim's solution can be extended to include leading and trailing whitespace and that should then do what you want as follows :-
^\s*[A-Za-z0-9]+(\s*,\s*[A-Za-z0-9]+)*\s*$
Presumably when you have validated the input string you will want to turn it into an array of tags to iterate over. You can do this as follows :-
array_var = string_var.delete(' ').split(',')
^([a-zA-Z0-9]+,\s*)*[a-zA-Z0-9]+$
Note that this regex doesn't match values with whitespace, so it won't match multiple words like "abc xyz, fgh qwe". It matches any amount of whitespace after commas. You might not need ^ or $ if validates_format_of tries to match the whole string, I've never used Rails so I don't know about that.
^[A-Za-z0-9]+([ \t]*,[ \t]*[A-Za-z0-9]+)*$
should match a CSV line that only contains those characters, whether it's just one value or many.

Resources