I am building a simple breadcrumb in ruby but I am not sure how to really implement my logic.
Let's say I have an array of words that are taken from my request.path.split("/) ["", "products", "women", "dresses"]
I want to push the strings into another array so then in the end I have ["/", "/products", "products/women", "products/women/dresses"] and I will use it as my breadcrumb solution.
I am not good at ruby but for now I came up with following
cur_path = request.path.split('/')
cur_path.each do |link|
arr = []
final_link = '/'+ link
if cur_path.find_index(link) > 1
# add all the previous array items with the exception of the index 0
else
arr.push(final_link)
end
end
The results should be ["/", "/products", "/products/women", "/products/women/dresses"]
Ruby's Pathname has some string-based path manipulation utilities, e.g. ascend:
require 'pathname'
Pathname.new('/products/women/dresses').ascend.map(&:to_s).reverse
#=> ["/", "/products", "/products/women", "/products/women/dresses"]
This is my simplest solution:
a = '/products/women/dresses'.split('/')
a.each_with_index.map { |e,i| e.empty? ? '/' : a[0..i].join('/') }
Using map and with_index it can be done like this:
arr = ["", "products", "women", "dresses"]
arr.map.with_index { |item, index| "#{arr[0...index].join('/')}/#{item}" }
This is another option using Enumerable#each_with_object and Enumerable#each_with_index:
ary = '/products/women/dresses'.split('/')
ary[1..].map
.with_index
.with_object([]) { |(folder, idx), path| path << [path[idx-1], folder].join('/') }.unshift('/')
Or also:
(ary.size - 1).times.map { |i| ary.first(i + 2).join('/') }.unshift('/')
Let's say I have a string like:
url = "https://example.com/user/tr_auth.php?key=34432&cmp_id=344&tr_id={user_id}"
I want to update the cmp_id=344 to be say cmp_id=44553. What's the best way to accomplish this? I can't gsub per say because I don't know what cmp_id might be equal, only that it will be a URL parameter in the string.
It seems like I want to do something like
uri = URI.parse(url)
params = CGI.parse(uri.query)
But then, how do I re-build the string swapping out the cmp_id parameter to be 44553?
Thanks!
If you are dealing with a web application (and/or Rails as the tag seems to indicate), then you certainly have Rack available. Rack::Utils has methods to parse and build a query.
url = "https://example.com/user/tr_auth.php?key=34432&cmp_id=344&tr_id={user_id}"
uri = URI.parse(url)
query = Rack::Utils.parse_query(uri.query)
# => {"key"=>"34432", "cmp_id"=>"344", "tr_id"=>"{user_id}"}
# Replace the value
query["cmp_id"] = 44553
uri.query = Rack::Utils.build_query(query)
uri.to_s
# => "https://example.com/user/tr_auth.php?key=34432&cmp_id=44553&tr_id=%7Buser_id%7D"
Also note that Rack, by default, escapes the query.
url = "https://example.com/user/tr_auth.php?key=34432&cmp_id=344&tr_id={user_id}"
uri = URI.parse(url)
params = CGI.parse(uri.query)
params['cmp_id'] = 44553
new_str = uri.host + uri.path + '?' + params.to_query
First, you can parse the url for params:
require 'cgi'
url = 'https://example.com/user/tr_auth.php?key=34432&cmp_id=344&tr_id={user_id}'
string_params = url.split('?')[1]
hash = CGI::parse(string_params)
Then you can iterate the hash by keys and change values:
hash.keys.each {|key| hash[key]='new value'}
url_params = hash.to_param
I'm needing to get secondary images for a product (which could have up to 10 images), but having a bit of an issue. Where the issue lies is secondary_images/#{id}_20.jpg. The _20 could be anything from _1 to _11 and _01 to _30. Unfortunately when the images were put into the system, they weren't 100% cohesive with the naming convention. I'd change the names, but there are over 50,000 images. What would be the proper way accomplish this?
*This code does work if the secondary_images/#{id} does end in _20.
def image_url(type = nil)
no_image = type.nil? ? 'no-image-lg.png' : 'no-image.png'
return "//img#{rand(0..9)}.foo.com/#{no_image}" unless has_image?
require 'net/http'
id = sprintf('%07d', master_product_id)
url = if type == 'secondaries'
"//img#{rand(0..9)}.foo.com/product_images/secondary_images/#{id}_20.jpg"
elsif type == 'thumbnail'
"//img#{rand(0..9)}.foo.com/product_images/thumbnails/#{id}.jpg"
else
"//img#{rand(0..9)}.foo.com/product_images/#{id}.jpg"
end
url = URI.parse(URI.encode(url.to_s))
req = Net::HTTP.new(url.host, url.port)
res = req.request_head(url.path)
res.code == '200' ? url.to_s : "//img#{rand(0..9)}.foo.com/#{no_image}"
end
def images
images = {}
images['main'] = image_url
images['thumbnail'] = image_url 'thumbnail'
images['secondaries'] = image_url 'secondaries'
images.to_dot
end
Thanks guys!
It's not pretty, but you can use the following regex to match the corresponding digits.
/.*(([1-9])|(0[1-9])|([1-3]\d))\.jpg\b/
Here's an example:
https://regex101.com/r/gJ2jU7/1
It's really difficult to tell what you want, but perhaps it'll help to know that Ruby includes routines that make it easy to get at the filename in a path. Once you have that it's easy to extract parts of the name since it's string manipulation.
def get_image_num(fname)
File.basename(fname, File.extname(fname)).split('_').last
end
[
'secondary_images/foo_1.jpg',
'secondary_images/foo_11.jpg',
'secondary_images/foo_01.jpg',
'secondary_images/foo_30.jpg',
'secondary_images/foo_20.jpg'
].map{ |s|
get_image_num(s)
}
# => ["1", "11", "01", "30", "20"]
If you need to get both the id value, and the file number, I'd do something like:
def get_image_num(fname)
File.basename(fname, File.extname(fname)).split('_')
end
[
'secondary_images/123_1.jpg',
'secondary_images/123_11.jpg',
'secondary_images/123_01.jpg',
'secondary_images/123_30.jpg',
'secondary_images/123_20.jpg'
].map{ |s|
get_image_num(s)
}
# => [["123", "1"], ["123", "11"], ["123", "01"], ["123", "30"], ["123", "20"]]
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