Fellow Stranger
Fellow Stranger

Reputation: 34113

How to set a local variable

I'm trying to create a vanity url in a callback based on a user's name with the following method:

before_create :generate_vanity_url

def generate_vanity_url
    vanity_url = self.name
    vanity_url.gsub!(/[^\w]/,"") 
end

The problem that occurs is that not only the variable vanity_url gets affected by the gsub! method, but the name attribute as well. What am I doing wrong?

Ps. the method is more extensive, but I have shortened it down for the purpose of clarity

Upvotes: 1

Views: 90

Answers (2)

Mulan
Mulan

Reputation: 135415

You don't have to use .dup, just don't use .gsub!

  • .gsub! is a destructive method, meaning it modifies the original.
  • .gsub is non-destructive and does not modify the original

So yeah, something like this should do the trick

before_create :generate_vanity_url

def generate_vanity_url
  @vanity_url = self.name.gsub /[^\w]/, "" 
end

Also \W is the same thing as [^\w] so do this instead

before_create :generate_vanity_url

def generate_vanity_url
  @vanity_url = self.name.gsub /\W/, "" 
end

~ % pry
[1] pry(main)> str = "hello world"
=> "hello world"
[2] pry(main)> str.gsub /o/, "a"
=> "hella warld"
[3] pry(main)> str
=> "hello world"
[4] pry(main)>

Upvotes: 7

Mike Szyndel
Mike Szyndel

Reputation: 10592

To my knowledge (which may be poor) this is a result of copy-on-write. Do like that

vanity_url = self.name.dup
vanity_url.gsub!(/[^\w]/,"")

Simple example in irb

without .dup...

> a = "asdf"
=> "asdf"
> b = a
=> "asdf"
> b.gsub!(/a/, 'q')
=> "qsdf"
> a
=> "qsdf"
> b
=> "qsdf"

... and with .dup

> a = "asdf"
=> "asdf"
> b = a.dup
=> "asdf"
> b.gsub!(/a/, 'q')
=> "qsdf"
> a
=> "asdf"
> b
=> "qsdf"

Upvotes: 3

Related Questions