What are Decorators? Decorators help extract view-specific business logic from models into decorator class. Here is an example code that puts view-specific business logic in the model:
app/models/user.rb
class User include Mongoid::Document def is_top_twenty? User.desc(:points).limit(20).include? self end end
app/controllers/profiles_controllers.rb
class ProfilesController < ApplicationController def show @user = User.find(params[:id]) end end
app/views/profiles/show.html.erb
<% if @user.is_top_twenty? %> <%= "#{@user.name} is in the top twenty" %> <% end %>
The problem with this code is that the method ‘is_top_twenty?’, which is only being used in the view is being declared in the User model. The User model is polluted with view-related logic.
One way to refactor this is to use decorators. By using decorators. we can remove the ‘is_top_twenty?’ method out of the model User and create a a UserDecorator class.
app/decorators/user_decorator.rb
class UserDecorator attr_reader :user def initialize(user) @user = user end def is_top_twenty? User.desc(:points).limit(20).include? user end end
Instead creating an instance variable of the User model in the controllers, we create an instance of UserDecorator class.
app/controllers/profiles_controllers.rb
class ProfilesController < ApplicationController def show user = User.find(params[:id]) @user_decorator = UserDecorator.new(user) end end
Now let’s see this in action on the view.
app/views/profiles/show.html.erb
<% if @user_decorator.is_top_twenty? %> <%= "#{@user_decorator.name} is in the top twenty" %> <% end %>
The code above will return an error since we don’t have the method for name yet. To fix this, you need to implement ‘method_missing’ function.
app/decorators/user_decorator.rb
class UserDecorator attr_reader :user def initialize(user) @user = user end def is_top_twenty? User.desc(:points).limit(20).include? user end def method_missing(method_name, *args, &block) post.send(method_name, *args, &block) end end
That’s it! Good luck on cleaning up your models.