Created
April 17, 2012 15:54
-
-
Save cmrichards/2407071 to your computer and use it in GitHub Desktop.
Data Model + Context + Role
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
The Context + Roles : | |
module Contexts | |
# Move an area to different points on the tree. | |
# | |
# This context has multiple entry points for each deviation of moving an area around the tree. | |
# | |
# The source area can be moved in any of these 3 ways : | |
# | |
# - Before an existing area. | |
# - After an existing area. | |
# - Within, ie in the subtree of, an existing area | |
# | |
class MoveArea < Contexts::Base | |
def initialize(area_id, target_area_id) | |
area = Area.find area_id | |
target_area = Area.find target_area_id | |
target_area_parent = target_area.parent | |
add_role :source_area, area, MoveableArea | |
add_role :target_area, target_area, MoveableAreaTarget | |
add_role :parent_of_target_area, target_area_parent, MoveableAreaTarget | |
end | |
def move_after_target_area | |
roles.source_area.move_after_target_area | |
end | |
def move_before_target_area | |
roles.source_area.move_before_target_area | |
end | |
def move_within_target_area | |
roles.source_area.move_within_target_area | |
end | |
end | |
module MoveableAreaTarget | |
def add_existing_sub_area(area) | |
area.parent = self | |
area.save! | |
end | |
end | |
# These role methods use some methods that are provided | |
# by the 'resort' gem that is used in the Area model : | |
# delete_from_list, append_to, prepend. | |
# | |
module MoveableArea | |
class CantMoveRoot < StandardError ; end | |
class InvalidMoveTarget < StandardError ; end | |
def move_after_target_area | |
check_target_area_not_in_subtree | |
check_not_root!(self) | |
check_not_root!(roles.target_area) | |
add_to_parent_of_target_area | |
self.append_to(roles.target_area) | |
end | |
def move_before_target_area | |
check_target_area_not_in_subtree | |
check_not_root!(self) | |
check_not_root!(roles.target_area) | |
add_to_parent_of_target_area | |
if roles.target_area.previous | |
self.append_to(roles.target_area.previous) | |
else | |
prepend | |
end | |
end | |
def move_within_target_area | |
check_target_area_not_in_subtree | |
check_not_root!(self) | |
delete_from_list | |
roles.target_area.add_existing_sub_area(self) | |
prepend # This method is from resort! gem, it moves the area to the top of the list. | |
end | |
private | |
#Add to the parent of the target area if the parent is different to the current parent. | |
def add_to_parent_of_target_area | |
if self.parent != roles.target_area.parent | |
delete_from_list | |
roles.parent_of_target_area.add_existing_sub_area(self) | |
end | |
end | |
#Check that area is not the root of the tree | |
def check_not_root!(area = self) | |
raise CantMoveRoot if area.parent.blank? | |
end | |
#Check that the target area is not within the subtree of the source area. | |
def check_target_area_not_in_subtree | |
raise InvalidMoveTarget if self.find_subtree(roles.target_area.id).exists? | |
end | |
end | |
------------------------ | |
The Domain Model : | |
class Area < ActiveRecord::Base | |
#https://github.com/codegram/resort | |
#Resort sorts elements within a list using a linked list format | |
resort! | |
# https://github.com/stefankroes/ancestry | |
# Ancestry arranges areas into a hierachy/tree of areas. | |
# has_ancestry provides the children and subtree methods. | |
has_ancestry | |
validates :name, :presence => true | |
has_many :sections | |
default_scope where(:expired=>false) | |
def find_section(section_id) | |
self.sections.where(:id=>section_id).first | |
end | |
def find_children(area_id) | |
self.children.where(:id=>area_id).first | |
end | |
def find_subtree(area_id) | |
self.subtree.where(:id=>area_id).first | |
end | |
def ordered_sections | |
self.sections.ordered | |
end | |
def ordered_areas | |
self.children.ordered | |
end | |
def expire | |
self.update_attribute :expired, true | |
end | |
def arranged_subtree | |
self.subtree.arrange | |
end | |
#TODO : make this nicer. The resort! gem automatically calls this #siblings method to determine | |
#what elements are in the same list. | |
#This method is required by the resort! gem. | |
def siblings | |
if self.ancestry.blank? | |
#Root children have no siblings, do don't return anything. Fix this ugliness. | |
super.where(:ancestry=>"xxxxxxxxxxxxxxxx") | |
else | |
#Call the siblings method that is added by the has_ancestry gem. | |
super | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment