DEV Community

alliecaton
alliecaton

Posted on

Mass Assignment in Ruby

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 
Enter fullscreen mode Exit fullscreen mode

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 
Enter fullscreen mode Exit fullscreen mode

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 
Enter fullscreen mode Exit fullscreen mode

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)