Ruby On Rails: Concatenate String in loop - ruby-on-rails

I am new to RoR. I was trying to find a way over googling to concatenate the string in a loop in Controller.
assets = Asset.where({ :current_status => ["active"] }).all
assets.each do |a|
string = string + ":"+ a.movie_title
end
I want to concatenate attribute "movie_title" as a string that would be colon separated.
but i get error
undefined method `+' for nil:NilClass

The easiest way is probably:
string = assets.collect(&:movie_title).join(':')
collect(&:movie_title) is the same as collect { |asset| asset.movie_title }, which returns an Array of the movie titles. join(':') creates a String with the values from the Array separated by :.

Try this
assets = Asset.where({ :current_status => ["active"] }).all
string = ""
if assets.present?
assets.each do |a|
string = string + ":"+ a.movie_title
end
end

Why not just this:
"#{string} : #{a.movie_title}"
If they are nil you will get " : "

Methods join (docs) and map (docs) may help you.
Try following:
assets = Asset.where(current_status: ["active"]).all
assets.map(&:movie_title).join(':')

Related

Make new array in controller by finding id

I have an array with Product Ids and Color HEX Codes
Input:
#campaign.selectedproducts
Output:
["2,333333","1,333333",4,444444"]
I'm trying to make a new array with all of the product data by finding it with id:
#selectedgifts = #campaign.selectedproducts.collect [{|i| Product.find(i) }, |i| i.split(',').last]
Array should output
["Product Object, HEX code", "Product Object, HEX code"]
¿Any help?
Thanks!
You can try with group_by method like below:
#campaign.selectedproducts.group_by(&:color_code).transform_values{|val| val.pluck(:id).uniq}
Converting Product object to string is not what you want i guess. So i suggest you storing each element as hash instead of string.
#campaign.selectedproducts.map do |string|
id, hex_code = string.split(',')
product = Product.find(id)
{ product => hex_code }
end
Edit: Or you can store each element as array like this:
#campaign.selectedproducts.map do |string|
id, hex_code = string.split(',')
product = Product.find(id)
[product, hex_code]
end

Refactoring processing of JSON attributes

In an API processing a large number of attributes, the following pattern is frequent
if !article[:ingredients].nil?
clean_ingredients = article[:ingredients].tr('*$+!##Â', ' ')
ingredients = clean_ingredients.downcase.capitalize
else
ingredients = nil
end
for a JSON string as: { "id": "YYYYYY", "article": [ { "ingredients": "long string", [...]
Unfortunately, a method defined as
def empty_and_clean(array_element, element_attribute)
if !array_element[:element_attribute].nil?
clean_ingredients = array_element[:element_attribute].tr('*$+!##Â', ' ')
ingredients = clean_ingredients.downcase.capitalize
else
ingredients = nil
end
end
cannot be called in the method as empty_and_clean(article, ingredients) as it returns
undefined local variable or method 'ingredients'
What syntax allows to refactor this pattern?
You can call your empty_and_clean method this way:
empty_and_clean(article, :ingredients)
Just modify empty_and_clean to use element_attribute directly rather than the symbol :element_attribute.
I suggest you read more about symbols in Ruby to understand how this works.
Also, array_element is a misleading name because it is an array, not an element of an array. array would be slightly better, but is still too generic. Maybe objects or something else that describes what is actually in the array.

Camelize up to a certain part of a string

I have:
s = "like_so__case"
camelize gives this:
s.camelize # => "LikeSoCase"
I'm looking for conversion up to a double underscore __ to get:
"LikeSo__case"
How can I camelize only up to a certain part of a string?
The simplest option is to gsub part of your string.
'like_so__case'.gsub(/(.*?)(__.*)/) { "#{$1.camelize}#{$2}" }
#=> "LikeSo__case"
UPDATE
Cleaner and faster way arising from comments.
'like_so__case__h'.sub(/(.*?)(?=__)/, &:camelize)
#=> "LikeSo__case__h"
s = "like_so__case"
=> "like_so__case"
s.split('__', 2).tap { |s| s[0] = s[0].camelize }.join('__')
=> "LikeSo__case"
You of course could wrap it in string method
For getting this LikeSo__case, we can do like:
s="like_so__case"
s.split('__').tap { |s| s[0] = s[0].camelize }.join('__')
Your description on the demand is not so clear.
From your excepted result, I understand it as 'camelize a part of string until a pattern'. I should note one thing first that camelize is not part of Ruby's standard library of class String. ActiveSupport::Inflector provides it.
So if you want to just camelize each part divided by a pattern, use str.split('_').map(&:capitalize).join('_'). In your case, it returns 'Like_So__Case'.
Ruby's String has another instance method named partition, which splits the string into three parts (an array):
Part before the pattern
The pattern
Part after the pattern
So str.partition('__').tap { |a| a[0] = a[0].split('_').map(&:capitalize).join }.join should be your answer in plain Ruby.
No need of relying on camelize. Simply, this:
"like_so__case"
.gsub(/_?([a-z])([a-z]*)(?=.*__)/i){$1.upcase + $2.downcase}
# => "LikeSo__case"
def camelize(s)
for i in 0..s.size-2 do
if s[i] == "_" and s[i+1] == "_"
next
elsif s[i] == "_" and s[i+1] != "_" and s[i-1] != "_"
s[i+1] = s[i+1].upcase
s[i] = ""
else
next
end
end
return s
end
Use this method to solve your problem
s = "like_so__case"
i = s.index('__')
#=> 7
s.tap { |s| s[0,i] = s[0,i].camelize }
#=> LikeSo__case
The last line could be replaced by two lines:
s[0,i] = s[0,i].camelize
s
If the original string is not to be mutated write
s.dup.tap { |s| s[0,i] = s[0,i].camelize }

Ruby split string

String = "Mod1:10022932,10828075,5946410,13321905,5491120,5030731|Mod2:22704455,22991440,22991464,21984312,21777721,21777723,21889761,21939852,23091478,22339903,23091485,22099714,21998260,22364832,21939858,21944274,21944226,22800221,22704443,21777728,21777719,21678184,21998265,21834900,21984331,22704454,21998261,21944214,21862610,21836482|Mod3:10828075,13321905,5491120,5946410,5030731,15806212,4100566,4787137,2625339,2408317,2646868,19612047,2646862,11983534,8591489,19612048,10249319,14220471,15806209,13330887,15075124,17656842,3056657,5086273|Mod4:10828075,5946410,13321905,5030731,5491120,4787137,4100566,15806212,2625339,3542205,2408317,2646862,2646868|Mod5:10022932;0.2512,10828075;0.2093,5030731;0.1465,5946410;0.1465,4787137;0.1465,2625339;0.0143,5491120;0.0143,13321905;0.0143,3542205;0.0143,15806212;0.0119,4100566;0.0119,19612047;0.0100,2408317;0.0100"
How can I split it out so that I can get each title(Mod1, Mod2..) and the ID's that belong to each title.
This is that I've tried so far, which is removing everything after the pipe, which I dont want.
mod_name = string.split(":")[0]
mod_ids = string.split(":")[1] #This gets me the ID's but also include the |Mod*
ids = mod_mod_ids.split("|").first.strip #Only returns Id's before the first "|"
Desired Output:
I need to save mod_name and mod_ids to their respective columns,
mod_name = #name ("Mod1...Mod2 etc) #string
mod_ids = #ids (All Ids after the ":" in Mod*:) #array
I think this does what you want:
ids = string.split("|").map {|part| [part.split(":")[0], part.split(":")[1].split(/,|;/)]}
There are a couple of ways to do this:
# This will split the string on "|" and ":" and will return:
# %w( Mod1 id1 Mod2 id2 Mod3 id3 ... )
ids = string.split(/[|:]/)
# This will first split on "|", and for each string, split it again on ":" and returs:
# [ %w(Mod1 id1), %w(Mod2 id2), %w(Mod3 id3), ... ]
ids = string.split("|").map { |str| str.split(":") }
If you want a Hash as a result for easy access via the titles, then you could do this:
str.split('|').inject({}){|h,x| k,v = x.split(':'); h[k] = v.split(','); h}
=> {
"Mod1"=>["10022932", "10828075", "5946410", "13321905", "5491120", "5030731"],
"Mod2"=>["22704455", "22991440", "22991464", "21984312", "21777721", "21777723", "21889761", "21939852", "23091478", "22339903", "23091485", "22099714", "21998260", "22364832", "21939858", "21944274", "21944226", "22800221", "22704443", "21777728", "21777719", "21678184", "21998265", "21834900", "21984331", "22704454", "21998261", "21944214", "21862610", "21836482"],
"Mod3"=>["10828075", "13321905", "5491120", "5946410", "5030731", "15806212", "4100566", "4787137", "2625339", "2408317", "2646868", "19612047", "2646862", "11983534", "8591489", "19612048", "10249319", "14220471", "15806209", "13330887", "15075124", "17656842", "3056657", "5086273"],
"Mod4"=>["10828075", "5946410", "13321905", "5030731", "5491120", "4787137", "4100566", "15806212", "2625339", "3542205", "2408317", "2646862", "2646868"],
"Mod5"=>["10022932;0.2512", "10828075;0.2093", "5030731;0.1465", "5946410;0.1465", "4787137;0.1465", "2625339;0.0143", "5491120;0.0143", "13321905;0.0143", "3542205;0.0143", "15806212;0.0119", "4100566;0.0119", "19612047;0.0100", "2408317;0.0100"]
}
Untested:
all_mods = {}
string.split("|").each do |fragment|
mod_fragments = fragment.split(":")
all_mods[mod_fragments[0]] = mod_fragments[1].split(",")
end
What I ended up using thanks to #tillerjs help.
data = sting.split("|")
data.each do |mod|
module_name = mod.split(":")[0]
recommendations = mod.split(":")[1]
end

using url in a string in ruby

I want to convert urls in a string to workable urls. For example:
str = "Hello, this is the link for yahoo: http://www.yahoo.com"
//in the view i have
<%= parse_description(r[:description]) %>
//in helper, i am splitting each word in the string and verifying if i have a string which
// contains http, if http is present then i am using link_to to make it a valid url:
def parse_description(str)
s = ""
str.split.each do |w|
a = w.include?("http") ? (link_to nil,"#{w}") : w
s += "#{a} "
end
end
once the string is returned back to the view, the link is not clickable. what wrong i am doing?
Thanks pst for your help.. while returning i just did s.html_safe.. it worked.
To match the URI's in a String use the following code:
html_string.scan(URI.regexp) do |*matches|
p $&
end

Resources