Rapid Prototyping with Rails: Lesson 4, ActiveSupport::Concerns
18 Nov 2014
DRYing up code with ActiveSupport::Concerns
1. Extract common code from Post/Comment Model abd place into Sluggable module
module Slugglable
extend ActiveSupport::Concern
included do
before_save :generate_slug!
end
def to_param
self.slug
end
def generate_slug!
the_slug = to_slug(self.title)
post = Post.find_by slug: the_slug
count = 2
while post && post != self
the_slug = append_suffix(the_slug, count)
post = Post.find_by slug: the_slug
count += 1
end
self.slug = the_slug.downcase
end
def append_suffix(str, count)
if str.split('-').last.to_i != 0
return str.split('-').slice(0...-1).join('-') + "-" + count.to_s
else
return str + "-" + count.to_s
end
end
def to_slug(title)
str = title.strip
str.gsub! /\s*[^A-Za-z0-9]\s*/, '-'
str.gsub! /-+/, "-"
str.downcase
end
end
2. One major problem with this is that the module has to work for both comments and posts
yet the model and column names are currently hardcoded.
The first fix is changing the class to thed class to self.class:
def generate_slug!
the_slug = to_slug(self.title)
post = self.class.find_by slug: the_slug
count = 2
while post && post != self
the_slug = append_suffix(the_slug, count)
post = self.class.find_by slug: the_slug
count += 1
end
3. Now to change the column names, you have to create a class method that we can call to
pass the column name:
module Slugglable
extend ActiveSupport::Concern
included do
before_save :generate_slug!
class_attribute: :slug_column
end
def to_param
self.slug
end
def generate_slug!
the_slug = to_slug(self.send(self.class.slug_column.to_sym))
post = self.class.find_by slug: the_slug
count = 2
while post && post != self
the_slug = append_suffix(the_slug, count)
post = self.class.find_by slug: the_slug
count += 1
end
self.slug = the_slug.downcase
end
def append_suffix(str, count)
if str.split('-').last.to_i != 0
return str.split('-').slice(0...-1).join('-') + "-" + count.to_s
else
return str + "-" + count.to_s
end
end
def to_slug(title)
str = title.strip
str.gsub! /\s*[^A-Za-z0-9]\s*/, '-'
str.gsub! /-+/, "-"
str.downcase
end
module ClassMethods
def sluggable_column(col_name)
self.slug_column = col_name
end
end
end
5. Replace the local variable, post
def generate_slug!
the_slug = to_slug(self.send(self.class.slug_column.to_sym))
obj = self.class.find_by slug: the_slug
count = 2
while obj && obj != self
the_slug = append_suffix(the_slug, count)
obj = self.class.find_by slug: the_slug
count += 1
end
self.slug = the_slug.downcase
end
6. Define sluggable_column in Post, User, and Category Models
sluggable_column :title
Rails Console Commands:
- Adds your rubygems api so you have to continuouasly log in.
- Lists gems that are remote