Why does string replace modifies the original variable value? - ruby-on-rails

9.3 I'm getting a strange behaviour and I cannot understand why:
s = self.shopify_p
s.title
=> "Disco (Wholesale)"
Right now I'd like to have a new variable with the content of s.title without the " (Wholesale)" part.
So I do the following:
original_title = s.title
=> "Disco (Wholesale)"
original_title[" (Wholesale)"] = ""
=> ""
Now if I do:
original_title
=> "Disco"
Which is ok but the strange thing is that it seems that the last string replace affected even the original s variable:
s.title
=> "Disco"
I really cannot understand this...can you tell me what is happening here?
s.title should still be "Disco (Wholesale)"...or not?

It is the same because you're accessing the same object.
irb(main):006:0> x = "aaaa"
=> "aaaa"
irb(main):007:0> y = x
=> "aaaa"
irb(main):008:0> x.object_id
=> 70358166435920
irb(main):009:0> y.object_id
=> 70358166435920
irb(main):010:0>
What you could do instead is
original_title = s.title.gsub(" (Wholesale)","")

After original_title = s.title both original_title and s.title reference the same object.
To actually copy the string either use Object#dup:
original_title = s.title.dup
dup → an_object
Produces a shallow copy of obj…
or String.new:
original_title = String.new(s.title)
new(str="") → new_str
Returns a new string object containing a copy of str.

Variables in ruby reference the objects they point to rather than copying them by default. So, if you change the underlying object, any changes will show up in any variables that contain a reference to that object.
If a, b, c and d all point to the same object, changes to any will "change" (be visible through) all of them.
a b c
\ | /
Object
|
d
If you want to keep your original value you'll need to somehow create a new variable.
irb(main):001:0> a = "Foo"
=> "Foo"
irb(main):002:0> b = a
=> "Foo"
irb(main):003:0> a << " Bar"
=> "Foo Bar"
irb(main):004:0> b
=> "Foo Bar"
irb(main):005:0> a
=> "Foo Bar"
irb(main):006:0> a += " Baz"
=> "Foo Bar Baz"
irb(main):007:0> a
=> "Foo Bar Baz"
irb(main):008:0> b
=> "Foo Bar"
For your case #wlad's gsub (note that he didn't use gsub!) suggestion seems like a good one.
original_title = s.title.gsub(" (Wholesale)","")

Related

Running Hash.new([]) does what you expect but not in the way you expect it [duplicate]

This question already has answers here:
Ruby hash default value behavior
(3 answers)
Closed last year.
So, I want to create a hash where any keys become arrays without having to separately declare them.
I therefore use
foo = Hash.new([])
=> {}
Then I can add items to keys that haven't been previously declared
foo[:bar] << 'Item 1'
=> ['Item 1']
There's just something odd about doing this. As when I call
foo
=> {}
to view the hash, it is empty. Even running
foo.keys
=> []
shows that it's empty.
However, if I run
foo[:bar]
=> ['Item 1']
Please make it make sense.
foo = Hash.new([]) sets the default value of a not existed key to an array. Herefoo[:bar] << 'Item 1' the :bar key doesn't exist, so foo uses an array to which you add a new element. By doing so you mutate the default value because the array is provided to you by a reference.
> foo = Hash.new([])
=> {}
> foo.default
=> []
If you call any not defined key on your hash you'll get this array:
> foo[:bar] << 'Item 1'
=> ["Item 1"]
> foo[:foo]
=> ["Item 1"]
To achieve your goal you should return a new array every time. It's possible by passing a block to Hash.new, the block will be executed every time you access a not defined key:
> foo = Hash.new { |hash, key| hash[key] = [] }
=> {}
> foo[:bar] << 'Item 1'
=> ["Item 1"]
> foo[:bar]
=> ["Item 1"]
> foo.keys
=> [:bar]
> foo[:foo]
=> []
> foo[:foo] << 'Item 2'
=> ["Item 2"]
> foo
=> {:bar=>["Item 1"], :foo=>["Item 2"]}
Here is the documentation.

Extract values from a string in Ruby

How to get a value from a string e.g
search_params[:price] = "1460,4500"
How can I get the first number into one variable and second into a different variable?
Did you mean this??:
first_price, second_price = search_params[:price].split(',')
You can use split method
irb(main):002:0> price = "1460,4500"
=> "1460,4500"
irb(main):003:0> price.split(',')
=> ["1460", "4500"]
irb(main):004:0> a, b = price.split(',')
=> ["1460", "4500"]
irb(main):005:0> a
=> "1460"
irb(main):006:0> b
=> "4500"

Why doesn't assigning a variable to an array yield expected results in Ruby?

Using IRB, I tested the following:
C:\Pickaxe>irb
irb(main):001:0> list_of_strings = %w{ a list of strings in an array }
=> ["a", "list", "of", "strings", "in", "an", "array"]
irb(main):002:0> a, b, c = list_of_strings
=> ["a", "list", "of", "strings", "in", "an", "array"]
irb(main):003:0> a
=> "a"
irb(main):004:0> b
=> "list"
irb(main):005:0> c
=> "of"
irb(main):006:0>
In the other languages I've developed in setting a, b, c = d sets the values of a, b and c to equal d in its entirety. Here they are set to successive elements in the array.
I don't understand how or why this works. Could someone shed light on the issue?
That's just how array assignment works in Ruby. It's trying to be clever, a little, by assigning each indexed item of the array to that variable on the left-hand side of the assignment =

Stuffing Hash in Array behaves differently using "var" rather than :var -- why?

Why do these snippets of code behave differently? I thought they were supposed to do the same thing...
foo = {}
array = []
foo['a'] = "1"
foo['b'] = "2"
array << foo
foo['a'] = "3"
foo['b'] = "4"
array << foo
output => [{"a"=>"3", "b"=>"4"}, {"a"=>"3", "b"=>"4"}]
This is not what I want. Fortunately, I tried using this format, which works:
foo = {}
array = []
foo = {
:a => "1",
:b => "2"
}
array << foo
foo = {
:a => "3",
:b => "4"
}
array << foo
output => [{:a=>"1", :b=>"2"}, {:a=>"3", :b=>"4"}]
What's going on here?
It's not " vs. : — it's that you're modifying foo (foo[...]=...) in the first example while you're reassigning the variable foo (foo=...) in the second. In the first example, foo still refers to the same object (which is also in the array) after you put in the values 3 & 4.
For a solution, I recommend the second option (which you can use with '/" (strings) or : (symbols), no matter), or alternatively you can do array << foo.clone to push a copy of foo onto the array, so further modifications won't change it.
In your first example, you push foo itself into the array. When you edit foo on the next few lines, you are editing the same hash which you just pushed into the array!
In your second example, you explicitly set foo to a new hash using the '{}' operators. So when you set the values of 'a' and 'b', you don't touch the original foo already pushed into the array.

Simplify Assignment in Ruby on Rails

I just want to assign the value of variable B to variable A only if B is not nil.
And I want to simplify the code as possible.
So I found the one.
A = B if B
But variable name is long such as data[:Symbol1][:Symbol2]... , anyhow same variable name is duplicated.
Can anybody help me with simplifying this code?
You might try the presence method.
Your code would look like
A = B.presence
Example of it in action:
[1] pry(main)> b = nil
=> nil
[2] pry(main)> a = b.presence
=> nil
[3] pry(main)> a
=> nil
[4] pry(main)> b = 'foo'
=> "foo"
[5] pry(main)> a = b.presence
=> "foo"
[6] pry(main)> a
=> "foo"
I'd say you need A = B || A.
The || operator evaluates and returns the first non-false operand. If B is "truthy", it will return B (and assign it to A). If B is false, A will just be assigned itself.
2 simple ways:
a = b.presence || a
Or
a = b || a

Resources