Created
September 7, 2011 19:38
-
-
Save adomokos/1201507 to your computer and use it in GitHub Desktop.
The supporting code for my blog entry: "Get out of my Controller! And from Active Record, too!"
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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