1. Not using associations properly
Say, we have association of College has many students, having foreign key college_id
in student table and the relation as below
class College < ApplicationRecord has_many :students end class Student < ApplicationRecord belongs_to :college end
Bad Practice:
Getting all students in a college
students = Student.where(college_id : 3)
Good Practice:
students = college.students
2. Hashes: Using fetch when key may not be present
Let's take an Hash called params below. Using dig is more efficient than fetch.
params = { "booking" => "flights", "trip_id" => "06574637", "refundable" => true }
Difference between fetch and dig
Fetch throws exception when key does not exist.
params.fetch("booking") => "flights" params.fetch("something") KeyError: key not found: "something" from (pry):22:in `fetch'
Dig throws nil even if key does not exist
params.dig("booking") => "flights" params.dig("something") => nil params.fetch("something", nil) => nil
So, I prefer using dig rather than fetch for avoiding exceptions in the code.
3. Using nil? always, rather than present?
nil?
returns false for empty array []
and empty string ""
. nil? only checks whether the variable or object is nil
or not.
[21] pry(main)> nil.nil? => true [22] pry(main)> "".nil? => false [23] pry(main)> [].nil? => false [24] pry(main)> {}.nil? => false [25] pry(main)> nil.present? => false [26] pry(main)> {}.present? => false [27] pry(main)> [].present? => false [28] pry(main)> nil.blank? => true [29] pry(main)> "".blank? => true [30] pry(main)> [].blank? => true [31] pry(main)> {}.blank? => true
blank?
is kinda opposite to present? and equally efficient.
4. Not using strong parameters
ActionController::Parameters inheriting from object class provides methods like params
, require
and permit
. It's always recommended to use strong parameters.
Allows you to choose which attributes should be whitelisted for mass updating and thus prevent accidentally exposing that which shouldn't be exposed. Provides two methods for this purpose: require and permit. The former is used to mark parameters as required. The latter is used to set the parameter as permitted and limit which attributes should be allowed for mass updating.
person_params = params[:person] Person.new(person_params)
Will take all attributes for mass updation. Whereas, using require and permit allows name and age attributes to be whitelisted.
Person.new(person_params) def person_params params.require(:person).permit(:name, :age) end
5. Using each when returning an array while looping
each
loops into each element in an array, whereas map
returns array of elements returned in each iteration.
array = [1, 2, 3, 4, 5, 6, 8, 9, 10] result = [] def select_even_nos array.each do |e| result << e if e.even? end result end
def select_even_nos result = array.map { |e| e if e.even? } end