Check whether a string contains numbers - ruby-on-rails

I have input values like:
string = "devid"
string = "devid123"
string = "devid.123.devid"
I need to sort strings that contain .(number)., for example "devid.123.devid". How can I separate only strings that consist of .(numbers). like .123.? Help me find a solution.
In a controller, I have:
#person = Person.new
personname = params['personname']
if personname.match("/\d+/")
#person.person_name = personname
#person.save()
result = 'true'
end
When I execute this code, I get "devid123" and "devid.123.devid".

If its certain that the format of the valid personname is always
<string>.<number>.<string>
You can try using :[regex, index] method for strings in ruby.
https://ruby-doc.org/core-2.6.1/String.html#method-i-5B-5D
So if
personname = "devid.123.devid"
s[/(.*)(\.\d+\.)(.*)/, 2] = ".123."
There are three different groups in the regex (.*)(\.\d+\.)(.*).
Matches anything
Matches a .<number>.
Matches anything
So based on this regex, the second group should provide you .<number>. which, I hope, is what you need.
Tested with Ruby 2.4.1

If I understand this correctly you only want a string where the digits are preceded by .. If so you need to modify your regex to be /\.\d+/
#person = Person.new
personname=params['personname']
if personname.match("/\.\d+/")
#person.person_name = personname
#person.save
result = 'true'
end
But this sounds like logic you should be handling in the model, since this is tagged as rails and not plain old ruby
controller
class PersonController
def create
if #person = Person.create(params)
result = 'true'
else
result = 'false'
end
# whatever you doing with result
end
end
person.rb
class Person < ApplicationRecord
validates :personname, format: { with: /\.\d+\./, message: 'must include digits' }
end
You can play with the regex # rubular

Related

i18n-tasks custom scanner for enums

I would like to create a custom scanner for i18n-tasks that can detect enums declared as hashes in models.
My enum declaration pattern will always be like this:
class Conversation < ActiveRecord::Base
enum status: { active: 0, archived: 1}, _prefix: true
enum subject: { science: 0, literature: 1, music: 2, art: 3 }, _prefix: true
end
The enums will always be declared as hashes, and will always have a numerical hash value, and will always have the option _prefix: true at the end of the declaration. There can be any number of values in the hash.
My custom scanner currently looks like this:
require 'i18n/tasks/scanners/file_scanner'
class ScanModelEnums < I18n::Tasks::Scanners::FileScanner
include I18n::Tasks::Scanners::OccurrenceFromPosition
# #return [Array<[absolute key, Results::Occurrence]>]
def scan_file(path)
text = read_file(path)
text.scan(/enum\s([a-zA-Z]*?):\s\{.*\W(\w+):.*\}, _prefix: true$/).map do |prefix, attribute|
occurrence = occurrence_from_position(
path, text, Regexp.last_match.offset(0).first)
model = File.basename(path, ".rb") #.split('/').last
name = prefix + "_" + attribute
["activerecord.attributes.%s.%s" % [model, name], occurrence]
end
end
end
I18n::Tasks.add_scanner 'ScanModelEnums'
However this is only returning the very last element of each hash:
activerecord.attributes.conversation.status_archived
activerecord.attributes.conversation.subject_art
How can I return all the elements of each hash? I am wanting to see a result like this:
activerecord.attributes.conversation.status_active
activerecord.attributes.conversation.status_archived
activerecord.attributes.conversation.subject_science
activerecord.attributes.conversation.subject_literature
activerecord.attributes.conversation.subject_music
activerecord.attributes.conversation.subject_art
For reference, the i18n-tasks github repo offers an example of a custom scanner.
The file scanner class that it uses can be found here.
This works:
def scan_file(path)
result = []
text = read_file(path)
text.scan(/enum\s([a-zA-Z]*?):\s\{(.*)}, _prefix: true$/).each do |prefix, body|
occurrence = occurrence_from_position(path, text,
Regexp.last_match.offset(0).first)
body.scan(/(\w+):/).flatten.each do |attr|
model = File.basename(path, ".rb")
name = "#{prefix}_#{attr}"
result << ["activerecord.attributes.#{model}.#{name}", occurrence]
end
end
result
end
It's similar to your 'answer' approach, but uses the regex to get all the contents between '{...}', and then uses another regex to grab each enum key name.
The probable reason your 'answer' version raises an error is that it is actually returning a three-dimensional array, not two:
The outer .map is an array of all iterations.
Each iteration returns retval, which is an array.
Each element of retail is an array of ['key', occurrence] pairs.
This isn't the answer, this is just the other attempt I made, which outputs a two dimensional array instead of a single array:
require 'i18n/tasks/scanners/file_scanner'
class ScanModelEnums < I18n::Tasks::Scanners::FileScanner
include I18n::Tasks::Scanners::OccurrenceFromPosition
# #return [Array<[absolute key, Results::Occurrence]>]
def scan_file(path)
text = read_file(path)
text.scan(/enum\s([a-zA-Z]*?):\s\{(.*)\}, _prefix: true/).map do |prefix, attributes|
retval = []
model = File.basename(path, ".rb")
names = attributes.split(",").map!{ |e| e.strip; e.split(":").first.strip }
names.each do |attribute|
pos = (Regexp.last_match.offset(0).first + 8 + prefix.length + attributes.index(attribute))
occurrence = occurrence_from_position(
path, text, pos)
name = prefix + "_" + attribute
# p "================"
# p type
# p message
# p ["activerecord.attributes.%s.%s" % [model, name], occurrence]
# p "================"
retval.push(["activerecord.attributes.%s.%s" % [model, name], occurrence])
end
retval
end
end
end
I18n::Tasks.add_scanner 'ScanModelEnums'
This however gives me an error for the second detected attribute:
gems/i18n-tasks-0.9.34/lib/i18n/tasks/scanners/results/key_occurrences.rb:48:in `each': undefined method `path' for ["activerecord.attributes.conversation.status_archived", Occurrence(app/models/project.rb:3:32:98::)]:Array (NoMethodError)

How to extract given array of string with numbers from string in groovy

I'm trying to check if commit-msg from git contains particular ticket number with project key of Jira using groovy in Jenkins pipeline
def string_array = ['CO', 'DEVOPSDESK', 'SEC', 'SRE', 'SRE00IN', 'SRE00EU', 'SRE00US', 'REL']
def string_msg = 'CO-10389, CO-10302 new commit'
To extract numbers I am using below logic.
findAll( /\d+/ )*.toInteger()
Not sure how to extract exact ticket number with project key.
Thanks in advance.
You could use Groovy's find operator - =~, combined with a findAll() method to extract all matching elements. For that, you could create a pattern that matches CO-\d+ OR DEOPSDESK-\d+ OR ..., and so on. You could keep project IDs in a list and then dynamically create a regex pattern.
Consider the following example:
def projectKeys = ['CO', 'DEVOPSDESK', 'SEC', 'SRE', 'SRE00IN', 'SRE00EU', 'SRE00US', 'REL']
def commitMessage = 'CO-10389, CO-10302 new commit'
// Generate a pattern "CO-\d+|DEVOPSDEKS-\d+|SEC-\d+|...
def pattern = projectKeys.collect { /${it}-\d+/ }.join("|")
// Uses =~ (find) operator and extracts matching elements
def jiraIds = (commitMessage =~ pattern).findAll()
assert jiraIds == ["CO-10389","CO-10302"]
// Another example
assert ("SEC-1,REL-2001 some text here" =~ pattern).findAll() == ["SEC-1","REL-2001"]
The regex can be assembled a bit simpler:
def projectKeys = ['CO', 'DEVOPSDESK', 'SEC', 'SRE', 'SRE00IN', 'SRE00EU', 'SRE00US', 'REL']
def commitMessage = 'CO-10389, REL-10302 new commit'
String regex = /(${projectKeys.join('|')})-\d+/
assert ['CO-10389', 'REL-10302'] == (commitMessage =~ regex).findAll()*.first()
You can have also another option with finer contol over matching:
def res = []
commitMessage.eachMatch( regex ){ res << it[ 0 ] }
assert ['CO-10389', 'REL-10302'] == res

How to convert string to existing attribute in model when creation

I got a array of strings, I want to retrieve for each the attribute during the creation of the post.
My array = ["_646_maturity", "_660_maturity", "_651_maturity", "_652_maturity", "_641_maturity"]
class Audit < ApplicationRecord
belongs_to :user
before_save :calculate_scoring
def calculate_scoring
scoring = []
models = ActiveRecord::Base.connection.tables.collect{|t| t.underscore.singularize.camelize.constantize rescue nil}
columns = models.collect{|m| m.column_names rescue nil}
columns[2].each do |c|
if c.include? "maturity"
Rails.logger.debug 'COLUMN : '+c.inspect
scoring.push(c)
end
end
getMaturity = ""
scoring.each do |e|
getMaturity = e.to_sym.inspect
Rails.logger.debug 'MATURITY : '+getMaturity
end
end
end
The log print > 'MATURITY : :_651_maturity'
I'm looking to the value of :_651_maturity who is a attribute of my post.
I tried .to_sym but it's not working..
Thanks for the help!
Inside calculate_scoring you can use self to point to the record you are saving. So self._651_maturity = <some_value>, self[:_651_maturity] = <some_value> and self['_651_maturity'] are all valid methods to set _651_maturity.
Also, you can do something like:
my_attrib = '_651_maturity'
self[my_attrib] = 'foo'

Too many checks for empty params. How to optimize queries to ActiveRecord in Rails5?

I'm doing checks for empty parameters before do the query.
There is only 1 check for params[:car_model_id]. I can imagine if I will add more checks for other params, then there will be a mess of if-else statements. It doesn't look nice and I think it can be optimized. But how? Here is the code of controller:
class CarsController < ApplicationController
def search
if params[:car_model_id].empty?
#cars = Car.where(
used: ActiveRecord::Type::Boolean.new.cast(params[:used]),
year: params[:year_from]..params[:year_to],
price: params[:price_from]..params[:price_to],
condition: params[:condition]
)
else
#cars = Car.where(
used: ActiveRecord::Type::Boolean.new.cast(params[:used]),
car_model_id: params[:car_model_id],
year: params[:year_from]..params[:year_to],
price: params[:price_from]..params[:price_to],
condition: params[:condition]
)
end
if #cars
render json: #cars
else
render json: #cars.errors, status: :unprocessable_entity
end
end
end
The trick would be to remove the blank values, do a little bit of pre-processing (and possibly validation) of the data, and then pass the params to the where clause.
To help with the processing of the date ranges, you can create a method that checks both dates are provided and are converted to a range:
def convert_to_range(start_date, end_date)
if start_date && end_date
price_from = Date.parse(price_from)
price_to = Date.parse(price_to)
price_from..price_to
end
rescue ArgumentError => e
# If you're code reaches here then the user has invalid date and you
# need to work out how to handle this.
end
Then your controller action could look something like this:
# select only the params that are need
car_params = params.slice(:car_model_id, :used, :year_from, :year_to, :price_from, :price_to, :condition)
# do some processing of the data
year_from = car_params.delete(:year_from).presence
year_to = car_params.delete(:year_to).presence
car_params[:price] = convert_to_range(year_from, year_to)
price_from = car_params.delete(:price_from).presence
price_to = car_params.delete(:price_to).presence
car_params[:price] = convert_to_range(price_from, price_to)
# select only params that are present
car_params = car_params.select {|k, v| v.present? }
# search for the cars
#cars = Car.where(car_params)
Also, I'm pretty sure that the used value will automatically get cast to boolean for you when its provided to the where.
Also, #cars is an ActiveRecord::Relation which does not have an errors method. Perhaps you mean to give different results based on whether there are any cars returned?
E.g: #cars.any? (or #cars.load.any? if you don't want to execute two queries to fetch the cars and check if cars exist)
Edit:
As mentioned by mu is too short you can also clean up your code by chaining where conditions and scopes. Scopes help to move functionality out of the controller and into the model which increases re-usability of functionality.
E.g.
class Car > ActiveRecord::Base
scope :year_between, ->(from, to) { where(year: from..to) }
scope :price_between, ->(from, to) { where(price: from..to) }
scope :used, ->(value = true) { where(used: used) }
end
Then in your controller:
# initial condition is all cars
cars = Cars.all
# refine results with params provided by user
cars = cars.where(car_model_id: params[:car_model_id]) if params[:car_model_id].present?
cars = cars.year_between(params[:year_from], params[:year_to])
cars = cars.price_between(params[:price_from], params[:price_to])
cars = cars.used(params[:used])
cars = cars.where(condition: params[:condition]) if params[:condition].present?
#cars = cars

Add extra filter parameters in RoR

Suppose I have a method in a controller:
def my_find(is_published, count)
items = Idea.where(published: is_published)
#......
end
Sometimes I want to pass some extra filter arguments
def my_find(is_published, count, some_extra_filter = nil)
items = Idea.where(published: is_published) #.where (some_extra_filter)
#......
end
where some_extra_filter can be lambda or just an plain sql "where" string and it can also be nil or "".
So how do I concatenate .where(published: is_published) with where (some_extra_filter) to get what I need?
This is actually very easy using scopes:
def my_find
#items = Idea.scoped
#items = #items.where(published: is_published) unless is_published.nil?
#items = #items.where(other: other_param) if other_params < 10
# etc, etc
end

Resources