Skip to content

Instantly share code, notes, and snippets.

@harssh-sparkway
Last active July 7, 2022 23:33
Show Gist options
  • Save harssh-sparkway/8707634 to your computer and use it in GitHub Desktop.
Save harssh-sparkway/8707634 to your computer and use it in GitHub Desktop.
Don’t Repeat Yourself (DRY) in Ruby on Rails
#Don’t Repeat Yourself (DRY) in Ruby on Rails
#DRY (Don’t Repeat Yourself) is a principle of Software Development to reducing repetition of information or codes. We can #apply DRY quite broadly to database schema, test plan, system, even documentation. And in this post, we will take example of DRY #in Ruby on Rails development.
#In particular case, if you find some methods whose definitions are more or less similar, only different by the method name, it #may use meta programming to simplify the things to make your model more clean and DRY. Consider this simple example where we #have an article with three states.
#Before
class Article < ActiveRecord::Base
def self.all_published
where("state = ?", "published")
end
def self.all_draft
where("state = ?", "draft")
end
def self.all_spam
where("state = ?", "spam")
end
def published?
self.state == 'published'
end
def draft?
self.state == 'draft'
end
def spam?
self.state == 'spam'
end
end
After
class Article < ActiveRecord::Base
STATES = ['draft', 'published', 'spam']
class <<self
STATES.each do |state_name|
define_method "all_#{state_name}" do
where("state = ?", state_name)
end
end
end
STATES.each do |state_name|
define_method "#{state_name}?" do
self.state == state_name
end
end
end
#When the DRY principle is applied successfully, a modification of any single element of a system does not require a change in #other logically unrelated elements. Additionally, elements that are logically related all change predictably and uniformly, and #are thus kept in sync. This makes your code more DRY and more clean. And adding more states makes it more easy to modify.
@hiro-riveros
Copy link

hiro-riveros commented Jan 22, 2019

or maybe by state?

class Article < ActiveRecord::Base
 
  def self.by_state(state)
     where(state: state)
   end
 
end

@rmurkute
Copy link

rmurkute commented Jul 2, 2020

More DRYing by using enums

class Article < ActiveRecord::Base
 
  enum state: [:draft, :published, :spam]
 
end

More info about enums ActiveRecord::Enum

Nice

@harry-wood
Copy link

I googled "Dry in rails" and came across this gist. Congratulations. It's ranking quite highly!

But I was googling that because there was a hackernews discussion today about people over-using the DRY principle, and some folks saying that Rails developers are the worst at this.

I do wonder if this gist is a case in point. Surely the "before" code is actually more readable than loops doing calls to define_method. Aren't we eliminating repetition at the cost of code clarity here?

The by_state(state) suggestion by @hiro-riveros is a lot cleaner, although that assumes we can change all the calling code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment