Instantly share code, notes, and snippets.

Embed
What would you like to do?
The supporting code for my blog entry: "Get out of my Controller! And from Active Record, too!"
module ActiveRecord; class Base; end; end
# The AR Models Rails give you
class User < ActiveRecord::Base
# These fields are defined dynamically by ActiveRecord
attr_accessor :id, :full_name
end
class Discussion < ActiveRecord::Base
# These fields are defined dynamically by ActiveRecord
attr_accessor :id, :title, :body, :comments
end
class Comment < ActiveRecord::Base
# These fields are defined dynamically by ActiveRecord
attr_accessor :id, :text, :entered_by
end
# The DTO models I use in my view
module DTO
class User
attr_reader :source_object, :id, :full_name
attr_accessor :comments
def initialize(source_object)
@source_object = source_object
@id = source_object.id
@full_name = source_object.full_name
end
end
class Discussion
attr_reader :source_object, :id, :title, :body, :comments
def initialize(source_object)
@source_object = source_object
@id = source_object.id
@title = source_object.title
@body = source_object.body
@comments = ::DTO::Comment.initialize_collection(source_object.comments)
end
end
class Comment
attr_reader :source_object, :id, :text, :entered_by
def initialize(source_object)
@source_object = source_object
@id = source_object.id
@text = source_object.text
@entered_by = @source_object.entered_by
end
def self.initialize_collection(source_objects)
source_objects.map do |source_object|
self.new(source_object)
end
end
end
end
# Services used in the app
module Service
class FindsDiscussion
def self.for(id)
# This is very high level
::DTO::Discussion.new(Discussion.find(id))
end
end
class FindsUsers
def self.all
User.all.map { |user| ::DTO::User.new(user) }
end
end
class SetsComments
def self.on_users(users, comments)
users.each do |user|
user.comments = comments.select do |comment|
user.source_object.id == comment.source_object.entered_by
end
end
end
end
end
class ApplicationController; end
class DiscussionsController < ApplicationController
attr_reader :users, :discussion
def index
@users = Service::FindsUsers.all
@discussion = Service::FindsDiscussion.for(params[:id])
Service::SetsComments.on_users(@users, @discussion.comments)
end
end
describe DiscussionsController do
subject { DiscussionsController.new }
it { should respond_to :index }
specify "index retrieves all the data for display" do
subject.stub(:params => {:id => 12})
discussion_dto = DTO::Discussion.new(Factory::ForDiscussion.make_one)
Service::FindsDiscussion.stub(:for).and_return discussion_dto
user_dummies = Factory::ForUser.make_two
user_dtos = user_dummies.map { |user_dummy| DTO::User.new(user_dummy) }
Service::FindsUsers.stub(:all).and_return user_dtos
Service::SetsComments.stub(:on_users).with(user_dtos, discussion_dto.comments)
# call the method under test
subject.index
end
end
# To keep the examples simple, I am not using FactoryGirl or Machinist
module Factory
class ForUser
def self.make_two
user1 = User.new
user1.id = 2
user1.full_name = 'User 1'
user2 = User.new
user2.id = 54
user2.full_name = 'User 2'
[user1, user2]
end
end
class ForDiscussion
def self.make_one
discussion = Discussion.new
discussion.id = 12
discussion.title = 'This is the discussion title'
discussion.body = 'This is the discussion body. I make it a little bit longer.'
discussion.comments = ForComment.make_two
discussion
end
end
class ForComment
def self.make_two
comments = []
comments << make_one
comments << make_one
comments.last.id = 33
comments.last.entered_by = 3
comments
end
def self.make_one
comment = Comment.new
comment.id = 32
comment.text = 'This is the comment test.'
comment.entered_by = 2
comment
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment