This morning, I had my first code review for my Ruby CLI project. During the review we went through my code and talked through the different files and methods that make up my project. The last portion of the review was dedicated to code refactoring where we focused on refactoring my initialize method for my Book
class. My original initialize method looked like this:
attr_accessor :title, :author, :rank, :description, :buy_links
def initialize(hash)
@title = title
@author = author
@description = description
hash.each do |key,value|
if key == "title"
self.send(("#{key}="), value)
elsif key == "rank"
self.send(("#{key}="), value)
elsif key == "author"
self.send(("#{key}="), value)
elsif key == "description"
self.send(("#{key}="), value)
elsif key == "buy_links"
self.send(("#{key}="), value)
end
end
save
end
Very smelly!!
The first thing we did was comment out the @title
, @author
, and @description
variable assignments at the top, as they were leftover from earlier code where I was not using mass assignment to initialize (yet). After that, the instructor asked me to look into the .respond_to?
Ruby method. After looking through the documentation, and with prompting from the instructor, we whittled my code down to look like this:
attr_accessor :title, :author, :rank, :description, :buy_links
def initialize(hash)
hash.each do |key,value|
if self.respond_to?(key)
self.send(("#{key}="), value)
end
end
save
end
When you call the respond_to?
method on an object, it will return true if the object responds to a given method. Another way I could think about my initialize with respond_to?
would be:
attr_accessor :title, :author, :rank, :description, :buy_links
def initialize(hash)
hash.each do |attr_key,attr_value|
if self.respond_to?(attr_key)
self.send(("#{attr_key}="), attr_value)
end
end
save
end
Thinking about it like this helps me conceptualize why I would be using the respond_to?
method here. Basically, I'm taking the hash passed into initialize, iterating over each key/value pair, and checking if my Book object (self) can respond to the writer/reader methods that attr_key corresponds to, AKA my self
object can be written/read through my attr_accessors.
The other method that we briefly spoke about was the send
method in Ruby. I knew what this method did in context of my applications, but I didn't know how it could be used in ways not directly related to mass assignment in my initialize. The instructor explained that send
is a method that is used to call other methods. Theoretically, I could create a custom method and use send
to call that method and arguments on an object, for example object.send :find_by_name, "Allie"
. Or in this case, use send to call a writer method that we interpolate the key we want to write into, and associate it with the key's value.
I definitely struggled with mass assignment conceptually in the last few weeks of the Ruby phase, so being forced to refactor my own code and digging into why certain methods are used in mass assignment (and how they can be used for other purposes) has definitely helped me gain a stronger understanding.
Top comments (0)