TechEnthu

Bad Programming practices in rails

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