i am trying to replace some word from a string with gsub function in ruby, but sometimes that works fine and in some cases giving this error? is there any issues with this format
NoMethodError (undefined method `gsub!' for nil:NilClass):
model.rb
class Test < ActiveRecord::Base
NEW = 1
WAY = 2
DELTA = 3
BODY = {
NEW => "replace this ID1",
WAY => "replace this ID2 and ID3",
DELTA => "replace this ID4"
}
end
another_model.rb
class Check < ActiveRecord::Base
Test::BODY[2].gsub!("ID2", self.id).gsub!("ID3", self.name)
end
Ah, I found it! gsub!
is a very weird method. Firstly, it replaces the string in place, so it actually modifies your string. Secondly, it returns nil
when no substitution has been made. This all sums up to the error you're getting.
The first time you execute that call, it modifies the string assigned to a constant, so it reads as "replace this 3 and name"
. When you try to run it for a second time, the first gsub
will fail to find a string it is looking for so will return nil
. The second gsub
is then executed on the nil.
On how to solve it - it all depends on what you're trying to achieve. For me, it is somewhat risky to change other class constants (breaks encapsulation). If you just want to get the result without modifying the original string, use gsub
(no bang). Or even better, convert those string into a method and use interpolation instead of substitution.
If the strings are just patterns, that should be replaced before get used. A better way would be string Interpolation.
class Test < ActiveRecord::Base
# Here use symbols instead, because symbols themselfs are immutable
# so :way will always equal :way
BODY = {
:new => "replace this %{ID1}",
:way => "replace this %{ID2} and %{ID3}",
:delta => "replace this %{ID4}"
}
end
# HERE you should create another constant based on the
# Test class constants
class Check < ActiveRecord::Base
BODY = {
:way => Test::BODY[:way] % {ID2: self.id, ID3: self.name}
}
# Or you can make it a method
def self.body
Test::BODY[:way] % {ID2: self.id, ID3: self.name}
end
end
this will change every apearance of the hash keys in the string
for example:
str = "%{num1} / %{num1} = 1"
str % {num1: 3} # 3 / 3 = 1
And like @BroiSatse said, you should not change constants of other classes or within the same class itself, at the end they are constants.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With