Raillery: Making Routing Even Easier
Programmers, just like all subcultures, have characteristics, some of which have been distilled via witticisms and aphorisms:
“A programmer is an organism that converts caffeine into code”
“There are no good programmers- only experienced ones”
“The best programmers are lazy and act dumb”
This last one really hits home. Why do in five lines what can be done in two? Or in one long line that can be done in one slightly shorter line? The world is full of problems that need to be solved, and in a world where the only abundant resource is scarcity, time is the most precious of all, and we’d rather not waste it. As the ubiquitous meme goes:
As a new recruit into the Ruby on Rails Army, I have experienced (undergone? endured?) the joys et al. of routing. While Rails is more concise and readable than Sinatra, which we Flatiron Mod 2 mods have flown to the moon (*groan*), there is still a lot of copy-and-paste. If programmers had a God, and said God had a stone tablet of Commandments, DRY (Don’t Repeat Yourselves) would be one of them. So, as DRY as Rails is, I think we can let it bake under the sun even more- at least for the basic tasks we’re doing so far.
I’m going to show you a few code snippets. See if you can find any patterns:
Index Pages
recipes/index.html.erb<% @recipes.each do |rec| %>
<div><%= link_to recipe.name, student_path(recipe) %></div>
<div><%= link_to recipe.ingredients, student_path(recipe) %></div>
<div><%= link_to recipe.cook_time, student_path(recipe) %></div>
<% end %># students/index.html.rb<% @students.each do |student| %>
<div><%=link_to student.first_name, student_path(student)%></div>
<div><%=link_to student.last_name, student_path(student)%></div>
<% end %>
Controller Files
# seas_controller.rbclass SeasController < ApplicationController def index
@seas = Sea.all
end
def show
@sea = Sea.find(params[:id])
end def new
@sea = Sea.new
end def edit
@sea = Sea.find(params[:id])
end def create
@sea = Sea.new(sea_params)
if @sea.save
redirect_to @sea
else
render 'new'
end
end def update
@sea = Sea.find(params[:id])
if @sea.update(sea_params)
redirect_to @sea
else
render 'edit'
end
end def destroy
Sea.destroy(params[:id])
redirect_to '/seas'
end private def sea_params
params.require(:sea).permit(:name, :temperature, :bio, :mood, :image_url, :favorite_color, :scariest_creature, :has_mermaids)
endend# student_class_controller.rbclass StudentsController < ApplicationControllerdef index
@students = Student.all
end
def show
@student = Student.find(params[:id])
enddef new
@student = Student.new
enddef edit
@student = Student.find(params[:id])
enddef create
@student = Student.new(student_params)
if @student.save
redirect_to @student
else
render 'new'
end
enddef update
@student = Student.find(params[:id])
if @student.update(student_params)
redirect_to @student
else
render 'edit'
end
enddef destroy
Student.destroy(params[:id])
redirect_to '/students'
endprivatedef student_params
params.require(:student).permit(:first_name, :last_name)
endend
That’s a lot of repetitive code! Even copying and pasting all into this article was a pain! Basically, only the class names (Student, Sea, Recipe) and the “columns” (member variables) of said classes are changing. The basic structure is darn near identical. So what can we do about it, besides hellishly moan, wail and grind our teeth?
As with everything else that we do more than once… we can automate it!
Here’s pseudo-code of some scripts that could take care of all this:
Controller Generator
def auto_controller(class_name, class_vars) def index
@class_name.lower = class_name.all
end def show
@class_name.lower = class_name.new
end def new
@class_name.lower = class_name.new
end def edit
@class_name.lower = class_name.find(params[:id])
end def create
@class_name.lower = class_name.new(class_name_params)
if @class_name.lower.save
redirect_to @class_name.lower
else
render 'new'
end
end def update
@class_name.lower = class_name.find(params[:id])
if @class_name.lower.update(class_name.lower.params)
redirect_to @class_name.lower
else
render 'edit'
end
end def destroy
@class_name.destroy(params[:id])
redirect_to '/class_name'
end private def class_name_params
params.require(:class_name).permit(class_vars)
endend
Index Generator
def auto_index(class_name, class_vars)
<% @class_name.each do |member| %>
for class_vars.each do |var|
<div><%=link_to member.first_name, student_path(member)%></div>
end
<% end %>
end
So rather than having to type the same either methods over and over, we could simply call the auto_controller method, and said scripts would be generated! After all, as the proverb goes, one line is better than 50.
Going through the process of manually entering these methods and scripts is a great way to ingrain the concepts in our malleable young (in dev years) brains… but Good Lawdy Lawd, I get it by now!! A script like mine could save all of us… dozens and dozens of minutes over the next few weeks! i.e. it could a life changer!
Or it could be a silly, overblown little made-up nothing… just like COVID!