I am trying to match the dynamic route with the help of the match method but it is not working.
["payment", "portal", "animation"].each do |arg|
define_method("profile_#{arg}") do
self.path.match("/users/\d+/#{arg}")
end
end
So, this code self.path.match("/users/\d+/#{arg}") doesn't work with interpolation.
Whereas If I do something like below then it works. So, is there any way to match the data dynamically
self.path.match('/users/\d+/payment')
self.path.match('/users/\d+/portal')
self.path.match('/users/\d+/animation')
The \d+ expression doesn't work properly with doublequotes and the string interpolation. Here a sample path for "portal" and 2x ways to match it. (Tested with 2.5.5)
path = "somedir/users/#{rand(0..999)}/portal"
["payment", "portal", "animation"].each do |arg|
define_method("profile_#{arg}") do
path.match("/users/"+(/\d+/).to_s+"/#{arg}")
# or
path.match('users/\d+/'+arg)
end
end
puts profile_payment
puts profile_portal
puts profile_animation
You can interpolate within a regexp literal itself.
?> s = "payment"
=> "payment"
>> %r(/users/\d+/#{s})
=> /\/users\/\d+\/payment/
Related
I want to perform an action if a string is contained, non-case-sensitively, in another string.
So my if statement would look something like this:
#a = "search"
if #a ILIKE "fullSearch"
#do stuff
end
You can use the include? method. So in this case:
#var = 'Search'
if var.include? 'ear'
#action
end
Remember include? method is case-sensitive. So if you use something like include? 'sea' it would return false. You may want to do a downcase before calling include?()
#var = 'Search'
if var.downcase.include? 'sea'
#action
end
Hope that helped.
There are many ways to get there. Here are three:
'Foo'.downcase.include?('f') # => true
'Foo'.downcase['f'] # => "f"
Those are documented in the String documentation which you need to become very familiar with if you're going to program in Ruby.
'Foo'[/f/i] # => "F"
This is a mix of String's [] slice shortcut and regular expressions. I'd recommend one of the first two because they're faster, but for thoroughness I added it because people like hitting things with the regex hammer. Regexp contains documentation for /f/i.
You'll notice that they return different things. Ruby considers anything other than false or nil as true, AKA "truthiness", so all three are returning a true value, and, as a result you could use them in conditional tests.
You can use a regexp with i option. i for insensitive I think.
a = "fullSearch"
a =~ /search/i
=> 4
a =~ /search/
=> nil
Or you could downcase your string and check if it's present in the other
a = "fullSearch"
a.downcase.include?('search')
=> true
I'm trying to match a string as such:
text = "This is a #hastag"
raw(
h(text).gsub(/(?:\B#)(\w*[A-Z]+\w*)/i, embed_hashtag('\1'))
)
def embed_hashtag('data')
#... some code to turn the captured hashtag string into a link
#... return the variable that includes the final string
end
My problem is that when I pass '\1' in my embed_hashtag method that I call with gsub, it simply passes "\1" literally, rather than the first captured group from my regex. Is there an alternative?
FYI:
I'm wrapping text in h to escape strings, but then I'm embedding code into user inputted text (i.e. hashtags) which needs to be passed raw (hence raw).
It's important to keep the "#" symbol apart from the text, which is why I believe I need the capture group.
If you have a better way of doing this, don't hesitate to let me know, but I'd still like an answer for the sake of answering the question in case someone else has this question.
Use the block form gsub(regex){ $1 } instead of gsub(regex, '\1')
You can simplify the regex to /\B#(\w+)/i as well
You can leave out the h() helper, Rails 4 will escape malicious input by default
Specify method arguments as embed_hashtag(data) instead of embed_hashtag('data')
You need to define embed_hashtag before doing the substitution
To build a link, you can use link_to(text, url)
This should do the trick:
def embed_hashtag(tag)
url = 'http://example.com'
link_to tag, url
end
raw(
text.gsub(/\B#(\w+)/i){ embed_hashtag($1) }
)
The correct way would be the use of a block here.
Example:
def embed_hashtag(data)
puts "#{data}"
end
text = 'This is a #hashtag'
raw(
h(text).gsub(/\B#(\S+)/) { embed_hashtag($1) }
)
Try last match regexp shortcut:
=> 'zzzdzz'.gsub(/d/) { puts $~[0] }
=> 'd'
=> "zzzzz"
Ruby => How to match a string that contains #and a number example #56
for example i have a string "my roll number is #256767"
i should match whether the string has # symbol and a number beside it
Use Ruby's match
!"my roll number is #256767".match(/#\d+/).nil?
Use something like:
m = s.match(/^.*(#\d+).*$/)
unless m.nil?
puts m[1]
end
I'm manually building an SQL query where I'm using an Array in the params hash for an SQL IN statement, like: ("WHERE my_field IN('blue','green','red')"). So I need to take the contents of the array and output them into a string where each element is single quoted and comma separated (and with no ending comma).
So if the array was: my_array = ['blue','green','red']
I'd need a string that looked like: "'blue','green','red'"
I'm pretty new to Ruby/Rails but came up with something that worked:
if !params[:colors].nil?
#categories_array = params[:colors][:categories]
#categories_string =""
for x in #categories_array
#categories_string += "'" + x + "',"
end
#categories_string.chop! #remove the last comma
end
So, I'm good but curious as to what a proper and more consise way of doing this would look like?
Use map and join:
#categories_string = #categories_array.map {|element|
"'#{element}'"
}.join(',')
This functionality is built into ActiveRecord:
Model.where(:my_field => ['blue','green','red'])
Are you going to pass this string on to a ActiveRecord find method?
If so, ActiveRecord will handle this for you automatically:
categories_array = ['foo', 'bar', 'baz']
Model.find(:all, :conditions => ["category in (?)", categories_array])
# => SELECT * FROM models WHERE (category in ('foo', 'bar', 'baz'))
Hope this helps.
If you are using the parameter hash you don't have to do any thing special:
Model.all(:conditions => {:category => #categories_array})
# => SELECT * FROM models WHERE (category in ('foo', 'bar', 'baz'))
Rails (actually ActiveSupport, part of the Rails framework) offers a very nice Array#to_sentence method.
If you are using Rails or ActiveSupport, you can call
['dog', 'cat', 'bird', 'monkey'].to_sentence # "dog, cat, bird, and monkey"
I want to write a function that allows users to match data based on a regexp, but I am concerned about sanitation of the user strings. I know with SQL queries you can use bind variables to avoid SQL injection attacks, but I am not sure if there's such a mechanism for regexps. I see that there's Regexp.escape, but I want to allow valid regexps.
Here is is the sample function:
def tagged?(text)
tags.each do |tag|
return true if text =~ /#{tag.name}/i
end
return false
end
Since I am just matching directly on tag.name is there a chance that someone could insert a Proc call or something to break out of the regexp and cause havoc?
Any advice on best practice would be appreciated.
Interpolated strings in a Regexp are not executed, but do generate annoying warnings:
/#{exit -3}/.match('test')
# => exits
foo = '#{exit -3}'
/#{foo}/.match('test')
# => warning: regexp has invalid interval
# => warning: regexp has `}' without escape
The two warnings seem to pertain to the opening #{ and the closing } respectively, and are independent.
As a strategy that's more efficient, you might want to sanitize the list of tags into a combined regexp you can run once. It is generally far less efficient to construct and test against N regular expressions than 1 with N parts.
Perhaps something along the lines of this:
class Taggable
def tags
#tags
end
def tags=(value)
#tags = value
#tag_regexp = Regexp.new(
[
'^(?:',
#tags.collect do |tag|
'(?:' + tag.sub(/\#\{/, '\\#\\{').sub(/([^\\])\}/, '\1\\}') + ')'
end.join('|'),
')$'
].to_s,
Regexp::IGNORECASE
)
end
def tagged?(text)
!!text.match(#tag_regexp)
end
end
This can be used like this:
e = Taggable.new
e.tags = %w[ #{exit-3} .*\.gif .*\.png .*\.jpe?g ]
puts e.tagged?('foo.gif').inspect
If the exit call was executed, the program would halt there, but it just interprets that as a literal string. To avoid warnings it is escaped with backslashes.
You should probably create an instance of the Regexp class instead.
def tagged?(text)
return tags.any? { |tag| text =~ Regexp.new(tag.name, Regexp::IGNORECASE) }
end