This content originally appeared on Level Up Coding - Medium and was authored by Kelsey Shiba
Things I learned on the job in the first 2 months
& — The Safe Operator
The “&” symbol is a great substitute for (:try) if you already know about that method. It basically translates to, “if this exists, then call the following method on it”. In code, this may look something like this:
chicken&.add_special_sauce
If the chicken object is not nil, it will call the add_special_sauce method on the chicken. If it is nil, this line will not error out.
Delegate
Delegate is a way to “delegate ” — or pass along methods from one model to another. In this example, we had the following relationships:
A Musician. Has the global_id we are looking to extract. (ex. musician.global_id)
A Gig. Belongs_to a musician. Has a musician_id.
A Client_Gig. Join table between the client and the gig. Has a gig_id and a client_id (not used).
A Songlist. Belongs to the client_gig. Has a client_gig_id.
We want to ask the Songlist model, “What is your musician’s global_id?” As you can imagine, there is a way to do this in long form:
songlist = Songlist.find (1234)
client_gig = ClientGig.find_by_id(songlist.client_gig_id)
gig = Gig.find_by_id(client_gig.gig_id)
musician = Musician.find_by_id(gig.musician_id)
musician.global_id = '0029e1b9-f20e-4f95-9db9-78f753edd1c5'
As you can see, that’s a lot of calls to the database, and quit a chunk of code. Instead we can create a method, called #musician_global_id, and we can delegate it from one model to another.
Since the musician already has the attribute global_id, we go first to the Gig model. We want to call this:
gig.musician_global_id
In ruby, we can actually delegate the #global_id method from the musician to the gig, like so:
#Gig.rb
delegate :global_id, to: :musician, prefix: :musician, allow_nil: true
We are delegating global_id, prefixing it with musician, therefore it becomes a method called #musician_global_id, and allowing it to return nil (optional, but helpful in certain situations), and it’s the Musician that is giving the Gig this method. So, let’s continue passing the torch through to the next relationship, which is between the Gig and the ClientGig.
#ClientGig.rb
delegate :musician_global_id, to: :gig, allow_nil: true
Make sense? Now that #musician_global_id exists on the Gig, we can delegate that method from the Gig to ClientGig, and allow nil (again, optional).
Finally, we allow the Songlist to know about that method, as it belongs to a client gig.
#Songlist.rb
delegate :musician_global_id, to: :client_gig, allow_nil: true
Now we have songlist.musician_global_id available to call. So, to recap, instead of this lengthy list of code:
songlist = Songlist.find (1234)
client_gig = ClientGig.find_by_id(songlist.client_gig_id)
gig = Gig.find_by_id(client_gig.gig_id)
musician = Musician.find_by_id(gig.musician_id)
musician.global_id = '0029e1b9-f20e-4f95-9db9-78f753edd1c5'
We can narrow everything down to a few lines of code to get the result:
songlist = Songlist.find (1234)
songlist.musician_global_id
We use delegate to reach through relationships to return a desired attribute, instead of writing a custom method in each of the models generating more code, which would’ve looked like so:
#Gig.rb
def musician_global_id(musician)
musician.global_id
end
#ClientGig.rb
def musician_global_id(gig)
gig.musician_global_id
end
#Songlist.rb
def musician_global_id(client_gig)
client_gig.musician_global_id
end
#frozen_string_literal: true
This comment exists at the top of most of the Ruby files that I see. It basically says that if there are any string literals in that file (ex:)
"Hi, Mom!"
They cannot be modified. It is as if the #freeze method was called on all of them, like so:
"Hi, Mom!".freeze
stringy = "Hi, Mom!"
stringy.freeze
Rake Tasks
I had no idea what a rake task was my first few weeks, and how useful they are to know about for real life use cases.
Rake tasks are basically a script or chunk of code that get defined with a description and a name. They can be name-spaced so you can be specific about how they are run from the terminal.
Let’s create a rake task for a real-life scenario. We need to take a CSV file and take the contents of it to create files in a database table that we have that already exists.
Steps to solve:
- Insert the CSV file into your code base
- Write a rake task to use that file to create records in the table
The CSV file would like like so (shortened):
First Name, Last Name, Instrument, Email
Kelsey,Shiba,Piano,kshiba@music.com
Bob,George,Trombone,bgeorge@music.com
Here’s the rake task:
namespace :db do
desc 'Updates fields for the list of musicians from data/musicians.csv'
task :add_musicians, %i[csv_file] => :environment do |_, args|
# rake db:add_musicians['path/to/file.csv']
abort('input file not found') unless args[:csv_file].present?
CSV.foreach(args[:csv_file], headers: true) do |row|
Musician.find_or_create_by!(
first_name: row['First Name'],
last_name: row['Last Name'],
instrument: row['Instrument'],
email: row['Email']
)
end
end
end
The rake task has a description, then a task name, that intakes a file (csv_file), stops the task if no file is entered, and the uses the Ruby class CSV to go through each row, and either find the record that already exists or create a new one with each of the information in each row.
We can call the rake task from the command line like so:
rake db:add_musicians['/data/musicians.csv']
Conclusion
I’m so excited to get to learn new things every day, and getting to share that information. Thanks for reading!
Ruby On-the-Job Training was originally published in Level Up Coding on Medium, where people are continuing the conversation by highlighting and responding to this story.
This content originally appeared on Level Up Coding - Medium and was authored by Kelsey Shiba
Kelsey Shiba | Sciencx (2021-04-30T01:25:21+00:00) Ruby On-the-Job Training. Retrieved from https://www.scien.cx/2021/04/30/ruby-on-the-job-training/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.