I have a Model user with the following method:
def number_with_hyphen
number&.insert(8, "-")
end
When I run it several times in my tests I get the following output:
users(:default).number_with_hyphen
"340909-1234"
(byebug) users(:default).number_with_hyphen
"340909--1234"
(byebug) users(:default).number_with_hyphen
"340909---1234"
(byebug) users(:default).number_with_hyphen
"340909----1234"
It changes the number ?Here are the docs https://apidock.com/ruby/v1_9_3_392/String/insert
When I restructure my method to:
def number_with_hyphen
"#{number}".insert(8, "-") if number
end
If works like expected. The output stays the same!
How would you structure the code, how would you perform the insert?
which method should I use instead. Thanks
If you're using the insert method, which in the documentation explicitly states "modifies str", then you will need to avoid doing this twice, rendering it idempotent, or use another method that doesn't mangle data.
One way is a simple regular expression to extract the components you're interested in, ignoring any dash already present:
def number_with_hyphen
if (m = number.match(/\A(\d{8})\-?(\d+)\z/))
[ m[1], m[2] ].join('-')
else
number
end
end
That ends up being really safe. If modified to accept an argument, you can test this:
number = '123456781234'
number_with_hyphen(number)
# => "12345678-1234"
number
# => "123456781234"
number_with_hyphen(number_with_hyphen(number))
# => "12345678-1234"
number_with_hyphen('1234')
# => "1234"
Calling it twice doesn't mangle anything, and any non-conforming data is sent through as-is.
Do a clone of the string:
"#{number}".clone.insert(8, '-')
Related
I have an array of parameters and i want to replace all parameters by looping over array in ruby on rails.
I am using before_action in controller as
before_action :cost_format
This is an array of parameters. The format of the parameter is string, i want to run a function on each parameter and convert it into float. So i am looping an array and calling function on each element.
def cost_format
x = [params[:cost_1], params[:cost_2], params[:cost_3]]
x.each do |i|
convert_cost(i)
end
end
I have a function convert_cost as following
def convert_cost(x)
x.gsub(',', '.').to_f
end
How do i loop an array so that my parameters get replaced.? Parameters are not being replaced by above code. Any hint would be appreciated.
Thanks
I think you'll want something like this:
def cost_format
%i(cost_1 cost_2 cost_3).each do |key|
params[key] = convert_cost(params[key])
end
end
def convert_cost(val)
val.gsub(',', '.').to_f
end
This grabs each key from your params and replaces the value with it passed through the convert_cost method.
Edit: you might be able to ignore this section about convert_cost due if it works with the format you're getting your numbers in. Please excuse my ethnocentrism :)
I've not updated your convert_cost method, though I'm a little wary about whether it will work at the moment. If you've got, for example "1,234,567" and you call your gsub you get "1.234.567". Calling to_f on that gives you 1.234, which I wouldn't think you'd want?
Instead of that, you could use:
def convert_cost(val)
val.gsub(',', '').to_f
end
E.G.
convert_cost("1,234,567")
# => 1234567.0
Combining all that, the following would be converted like so:
params = { cost_1: "1,234,567", cost_2: "123", cost_3: "456.5", cost_4: "I won't be touched" }
# after `cost_format` before_action runs:
# => {:cost_1=>1234567.0, :cost_2=>123.0, :cost_3=>456.5, :cost_4=>"I won't be touched"}
Let me know how you get on or if you have any question - hope this helps.
Could you try something like
x.map{|param| param.gsub(',', '.').to_f}
directly on your array.
So your cost_format method will look like:
def cost_format
x = [params[:cost_1], params[:cost_2], params[:cost_3]]
result = x.map{|param| param.gsub(',', '.').to_f}
# do stuff with result
end
I think the reason it's not working because, each method returns its receiver, but map returns a new array.
Is it possible to dynamically create key names of a hash? I'm passing the following hash parameters:
params[:store][:store_mon_open(5i)]
params[:store][:store_mon_closed(5i)]
params[:store][:store_tue_open(5i)]
params[:store][:store_tue_closed(5i)]
.
.
.
params[:store][:store_sun_open(5i)]
params[:store][:store_sun_closed(5i)]
To check if each parameter exists, I'm using two arrays:
days_of_week = [:mon, :tue, ..., :sun]
open_or_closed = [:open, :closed]
But, I can't seem to figure out how to dynamically create the params hash (the second key( with the array. Here's what I have so far:
days_of_week.each do |day_of_week|
open_or_closed.each do |store_status|
if !eval("params[:store][:store_#{day_of_week}_#{store_status}(5i)").nil
[DO SOMETHING]
end
end
end
I've tried a bunch of things including the eval method (as listed above) but rails seems to dislike the parentheses around the "5i". Any help is greatly appreciated!
You should be able to do
if params[:store]["store_#{day_of_week}_#{store_status}(5i)".to_sym]
Note that you were missing the ? on .nil? and that !object.nil? can be shortened to just object
Assuming this is a HashWithIndifferentAccess, you should be able to access it via string just as you could with a symbol. Thus:
days_of_week.each do |day_of_week|
open_or_closed.each do |store_status|
key = "store_#{day_of_week}_#{store_status}(5i)"
unless params[:store][key]
# DO SOMETHING
end
end
end
If it's not a HashWithIndifferentAccess then you should just be able to call key.to_sym to turn it into a symbol.
There is already created record, like
Company "Life"
How to make this record to the species
сompany-life
I used parameterize, but it turns:
company-quot-life-quot
As I understand, .gsub(""", "") is not suitable for implementation, since to create too large list of exceptions
Is there may be a way to make record in raw format? (to parameterize later)
thanks in advance!
Here is a non-Rails approach:
require 'cgi'
str = 'Company "Life"'
puts CGI.unescape_html(str).gsub(/"/, '').gsub(/\s+/, '-').downcase
# => company-life
And a pure regex solution:
puts str.gsub(/&\w+;/, '').gsub(/\s+/, '-').downcase
# => company-life
And if you are inside Rails(thanks to #nzifnab):
str.gsub(/&\w+;/, '').parameterize
As #meager said, you shouldn't be storing the html-encoded entities in the database to begin with, how did it get in there with "? Theoretically this would work:
class Page < ActiveRecord::Base
before_validation :unescape_entities
private
def unescape_entities
self.name = CGI.unescape_html(name)
end
end
But I'm still curious how name would be getting there in the first place with html entities in it. What's your action/form look like?
"Company "Life"".html_safe.parameterize
"Company "Life"".gsub(/&[^;]+;/, "-").parameterize.downcase
# => "company-life"
Firstly, gsub gets rid of html entities, then parameterize gets rid from all but Ascii alphanumeric (and replaces them with dash), then downcase. Note that "_" will be preserved too, if you don't like them, another gsub('_', '-') is needed.
I want to print numbers in my rails application with commas. As per the answer here, I could wrap every single number I print with
number_with_delimiter(#number, :delimiter => ',')
However, I don't want to go into my views and apply this manually. I'd much rather override the way integers are printed.
In java/jsp, anything inside a <%= %> tag gets a toString() call to evaluate what is printed on the page, so I figured that overriding the to_s method for the Integer class would do:
class Integer
def to_s
number_with_delimiter(self, :delimiter => ',')
end
end
Unfortunately, this doesn't work in that the numbers printed using the <%=%> tag don't appear with commas. (No errors are raised.)
How do I get this right? Does the <%=%> block not automagically call a to_s method on the given object? How does it evaluate what to print?
You're monkey patching the wrong thing, you want to patch Fixnum. For example:
>> class Fixnum
>> def to_s
>> 'pancakes'
>> end
>> end
=> nil
>> 1.to_s
=> "pancakes"
and for ERB:
>> ERB.new('<%= 11 %>').result
=> "pancakes"
That said, your shortcut (like most shortcuts) will probably end up causing you various new and interesting problems elsewhere. You will end up sending '1,000' to something (such as a database or client-side JavaScript or ...) that expects '1000' and you'll get a confusing hissy fit for your efforts. You'll also have to worry about the other numeric classes such as Float and Bignum.
Fix your views, don't kludge around your own laziness.
Student.find(:all, :conditions => [‘name = ? and status = ?’ ‘mohit’, 1])
Vs
Student.find_all_by_name_and_status(‘mohit’, 1)
Both the queries will result the same set of row but first one is preferable cause in the second way there will be exception generated method_missing and then rails will try to relate it as dynamic method. if fine then result set to returned.
Can any body explain me this in a good manner. What exactly is happening behind the screen. Please correct me if i am wrong.
You are right, the second way will go through a method_missing. ActiveRecord will parse the method name and if it is a valid name, it will generate a method on the fly.
If you look in the source of ActiveRecord::Base, in method_missing you'll see that developers left us a comment of how this generated method would look like:
# def self.find_by_login_and_activated(*args)
# options = args.extract_options!
# attributes = construct_attributes_from_arguments(
# [:login,:activated],
# args
# )
# finder_options = { :conditions => attributes }
# validate_find_options(options)
# set_readonly_option!(options)
#
# if options[:conditions]
# with_scope(:find => finder_options) do
# find(:first, options)
# end
# else
# find(:first, options.merge(finder_options))
# end
# end
So you see that generally it boils down to the same find method.
I would not say that the first way is preferable because of method_missing, because the performance penalty for that is negligible. The second way reads better and works well if you just need to fetch records based on attributes equal to some values.
However, this second form does not allow you to do anything beyond equality comparison (e.g., range comparison, "not equal to" expressions, joins, etc.). In such cases, you'll just have to use the find method with appropriate conditions and other parameters.