Mass Assignment in Ruby 
Published: 2021-01-14 22:15:29

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.