How to use #{} without converting array to string - ruby-on-rails

I have this code block.
query = ['an','array']
#a = params[:action] == 'show' ? "paid" : "paid_students"
variable = "Student.#{#a}(#{query})"
eval(a)
But when I run this I am getting "variable" value as
Student.paid('anarray')
The array is converted to string.How can I avoid this. pls help

The #{} symbol is string interpolation. Its entire purpose is to turn an object into a string and interpolate it into another string. If you want to turn it into a different kind of string, you can certainly do that. For example, if you want to turn it into the string "[1, 2, 3]", you can do variable = "Student.#{#a}(#{query.inspect})".
But a better way to do what you're trying to do would be this:
query = ['an','array']
#a = params[:action] == 'show' ? :paid : :paid_students
Student.send(#a, query)
For more information, see the Ruby Object#send documentation.

variable = "Student.#{#a}(query)"
Doesn't work?

Related

Ruby to_s isn't converting integer to string

I'm trying to convert some values in a hash into a string but the type stays the same.
recommended_stores = []
results['data'].each do |stores_list|
stores_list['stores'].each do |store|
store['id'].to_s
end
recommended_stores << stores_list['stores']
end
Am I missing something here?
the method #to_s just returns the element converted to a string, but does not actually convert the element to a string permanently. instead of using #each, you could use #map, like this.
results['data'].map do |stores_list|
stores_list['stores'].each do |store|
store['id'] = store['id'].to_s
end
end
That would return an array of arrays, if you want it to be just one array you can use #flat_map.
you got everything but you are not storing it, i think assigning the value of hash with the value.to_s would work, can you try as below
recommended_store = []
results['data'].each do |stores_list|
stores_list['stores'].each do |store|
store['id'] = store['id'].to_s
end
recommended_store << stores_list['stores']
end
Note : in your question array declared is "recommended_store" and last line you are pushing elements in to "recommended_stores" hope its just a typo, and not the cause of problem :-)

Converting array with .join not saving value

I have a method do_stuff that takes a string as a value. However, an array of two strings is occasionally passed in. In this situation, I need to convert the array to a single string (without commas). So for example, ["hello", "world"] should become "hello world".
So, if value = array, join the two strings, otherwise leave it alone.
The following line I have does what I want, but I am struggling with actually "saving" the value before passing it to the method do_other_stuff.
def do_stuff(value)
value.join("") if value.is_a? Array
do_other_stuff(value)
end
So I think i am close, but what would be the best way to ensure value is manipulated before passing it to do_other_stuff ?
join does not change your object, you're wasting its return value
value = value.join if value.is_a? Array
Note that "" is the default for the join parameter, so I got rid of it
Replace
value.join("") if value.is_a? Array
With
value = value.join("") if value.is_a? Array
Basically you need to reassign result back to value
Use duck typing instead of checking the class:
def do_stuff(value)
do_other_stuff(value.try(:join, '') || value)
end
.try is from ActiveSupport and will return nil if the object does not respond to the method. In plain old ruby you would write this as:
def do_stuff(value)
do_other_stuff(value.respond_to?(:join) ? value.join("") : value)
end

Regular expression to explode the URLs

When I am trying to explode the url from one string, its not returning the actual URL. Please find the def I have used
def self.getUrlsFromString(str="")
url_regexp = /(?:http|https):\/\/[a-z0-9]+(?:[\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(?:(?::[0-9]{1,5})?\/[^\s]*)?/ix
url = str.split.grep(url_regexp)
return url
rescue Exception => e
DooDooLogger.log(e.message,e)
return ""
end
when I do self.getUrlsFromString(" check this site...http://lnkd.in/HjUVii") it's returning
site...http://lnkd.in/HjUVii
Instead of
http://lnkd.in/HjUVii
It's because grep in Array class returns an array of every element for element === pattern, so
str.split.grep(/http/ix)
will return ["site...http://lnkd.in/HjUVii"] too.
You can try instead of
str.split.grep(url_regexp)
something like this:
url_regexp.match(str).to_s
Should not you use something much simpler as regex like:
/((http|https):[^\s]+)/
If you want to find all occurences in a string, you could use String#scan:
str = "check these...http://lnkd.in/HjUVii http://www.google.com/"
str.scan(url_regexp)
=> ["http://lnkd.in/HjUVii", "http://www.google.com/"]

Append query string to url

I have a callback url string params[:callback] and I need to append a query string "&result=true" and redirect the user. The better way I found of doing this is using addressable but I think the code is too big for task like this especially when we are talking about ruby:
callback = Addressable::URI.parse(params[:callback])
query = callback.query_values
query[:result] = 'true'
callback.query_values = query
redirect_to callback.to_s
Is there a more elegant way of getting the same result as this snippet?
I wan't to bring update to this topic, because any of the solutions didn't work me.
The reason being, that it seems that callback.query_values returns Nil if the actual url doesn't have existing query values.
Therefore if you have urls such as: http://www.foo.com and http://www.foo.com?bar=1 you should use the following code:
url = "http://www.foo.com" # or params[:callback] obviously. :)
callback = Addressable::URI.parse(url)
callback.query_values = (callback.query_values || {}).merge({
result: true
})
redirect_to callback.to_s
Cheers.
if you don't need any URL validations you can do this (looks a little bit dirty):
url = params[:callback]
redirect_to url + (url.include?('?') ? '&' : '?') + 'result=true'
otherwise you have to use either some external library (like Addressable) or URI module from standard library
callback.query_values = callback.query_values.merge({"result" => "true"})
I think you're pretty close to optimal. you could crush out a line or two,
but it doesn't really gain you anything.
callback = Addressable::URI.parse(params[:callback])
callback.query_values = callback.query_values.merge {:results => 'true' }
redirect_to callback.to_s
If the callback is always inside your application, you might have some other options with varying degrees of coolness, but you didn't specify if that was the case or not.
years later, I find a better solution of this problem.
Get the value from the super first, then do any tweaks we need using Addressable
def url_for(options={})
val = super
if params[:locale].present?
parsed = Addressable::URI.parse(val)
query_array = parsed.query_values(Array) || []
query_array << ['locale', params[:locale]]
parsed.query_values = query_array
val = parsed.to_s
end
val
end
Let me offer this one modestly. I suggest using only strings for query parameters keys and values (like Arye noted) . Also, NilClass instances have a to_h method, which allows to remove some brackets:
callback = Addressable::URI.parse(params[:callback])
callback.query_values = callback.query_values.to_h.merge("result" => "true")
redirect_to callback.to_s
You can try with merge
request.parameters.merge({:result => true})
this will add your parameter to the ones already defined.

Is it possible to have variable find conditions for both the key and value?

I'm trying to pass in both the field and the value in a find call:
#employee = Employee.find(:all,
:conditions => [ '? = ?', params[:key], params[:value].to_i)
The output is
SELECT * FROM `employees` WHERE ('is_manager' = 1)
Which returns no results, however when I try this directly in mysqsl using the same call without the '' around is_manager, it works fine. How do I convert my params[:key] value to a symbol so that the resulting SQL call looks like:
SELECT * FROM `employees` WHERE (is_manager = 1)
Thanks,
D
If you want to convert a string to symbol(which is what params[:key] produces, all you need to do is
params[:key].to_s.to_sym
2 points:
A word of caution : symbols are
not garbage collected.
Make sure your key is not a
number, if you convert to_s first
then to_sym, your code will work but
you may get a wierd symbol like
this:
:"5"
You could use variable substitution for column name instead of using bind values:
# make sure the key passed is a valid column
if Employee.columns_hash[params[:key]]
Employee.all :conditions => [ "#{params[:key]} = ?", params[:value]]
end
You can further secure the solution by ensuring column name passed belongs to a pre selected set.:
if ["first_name", "last_name"].include? [params[:key]]
Employee.all :conditions => [ "#{params[:key]} = ?", params[:value]]
end
"string".to_sym

Resources