From 8cdb204a9446f16b28dd0cb5024bcd82846a6d36 Mon Sep 17 00:00:00 2001
From: Mark Moser <MarkAMoser@gmail.com>
Date: Sat, 3 Oct 2015 08:04:16 -0500
Subject: [PATCH] adding some parent CRUD

---
 Gemfile                                     |  1 +
 Gemfile.lock                                |  3 ++
 app/controllers/parents_controller.rb       | 32 +++++++++++++++++++--
 app/controllers/relationships_controller.rb | 19 ++++++++++++
 app/models/child.rb                         | 11 +++++++
 app/models/person.rb                        |  3 +-
 app/views/parents/index.html.haml           |  4 ++-
 app/views/parents/new.html.haml             | 21 ++++++++------
 app/views/parents/show.html.haml            | 23 +++++++++++++--
 config/routes.rb                            |  4 +++
 10 files changed, 106 insertions(+), 15 deletions(-)
 create mode 100644 app/controllers/relationships_controller.rb

diff --git a/Gemfile b/Gemfile
index 084fc05..7597d1c 100644
--- a/Gemfile
+++ b/Gemfile
@@ -13,6 +13,7 @@ gem 'uglifier', '>= 1.3.0'
 gem 'jquery-rails'
 gem 'turbolinks'
 gem 'haml-rails', "~> 0.9"
+gem 'actionview-encoded_mail_to'
 
 # gem 'rabl-rails', '~> 0.4.1'
 # gem 'jbuilder', '~> 2.0'
diff --git a/Gemfile.lock b/Gemfile.lock
index 619003c..92e8a04 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -20,6 +20,8 @@ GEM
       erubis (~> 2.7.0)
       rails-dom-testing (~> 1.0, >= 1.0.5)
       rails-html-sanitizer (~> 1.0, >= 1.0.2)
+    actionview-encoded_mail_to (1.0.7)
+      rails
     activejob (4.2.4)
       activesupport (= 4.2.4)
       globalid (>= 0.3.0)
@@ -245,6 +247,7 @@ PLATFORMS
   ruby
 
 DEPENDENCIES
+  actionview-encoded_mail_to
   awesome_print
   bcrypt (~> 3.1.7)
   binding_of_caller
diff --git a/app/controllers/parents_controller.rb b/app/controllers/parents_controller.rb
index 85c9c45..573c3f3 100644
--- a/app/controllers/parents_controller.rb
+++ b/app/controllers/parents_controller.rb
@@ -5,14 +5,40 @@ class ParentsController < ApplicationController
   end
 
   def show
-    @parent = Person.just_parents.where(id: params[:id])
+    @parent = Person.includes(:children).find_by_id(params[:id])
+    @more_children = Child.not_related_to(@parent.id)
   end
 
   def new
+    @parent = Person.new
+    3.times { @parent.children.build }
   end
 
   def add
-    ap params
-    redirect_to list_parents_path
+    @parent = Person.create add_parent_params
+
+    if @parent.persisted?
+      redirect_to parent_path(@parent), notice: 'Success!'
+      return
+    else
+      render :new
+    end
   end
+
+  def edit
+    @parent = Person.includes(:children).find_by_id(params[:id])
+    @more_children = Child.all
+  end
+
+  private
+
+    def add_parent_params
+      params.require(:parent).permit(
+        :first_name,
+        :last_name,
+        :phone,
+        :email,
+        children_attributes: [:first_name, :last_name]
+      )
+    end
 end
diff --git a/app/controllers/relationships_controller.rb b/app/controllers/relationships_controller.rb
new file mode 100644
index 0000000..f46a36e
--- /dev/null
+++ b/app/controllers/relationships_controller.rb
@@ -0,0 +1,19 @@
+class RelationshipsController < ApplicationController
+  def add_child
+    parent = Person.find(params[:parent])
+    child = Child.find(params[:child])
+
+    parent.parenthoods.create(child)
+
+    redirect_to :back, notice: 'Child added to parent!'
+  end
+
+  def del_child
+    parent = Person.find(params[:parent])
+    child = Child.find(params[:child])
+
+    parent.parenthoods.find_by_child_id(child.id).destroy
+
+    redirect_to :back, notice: 'Child removed from parent!'
+  end
+end
diff --git a/app/models/child.rb b/app/models/child.rb
index 6ad0104..54c72d3 100644
--- a/app/models/child.rb
+++ b/app/models/child.rb
@@ -5,6 +5,17 @@ class Child < ActiveRecord::Base
   validates :first_name, presence: true
   validates :last_name, presence: true
 
+  scope :not_related_to, lambda { |parent_id|
+    joins("LEFT JOIN (
+          SELECT child_id
+          FROM parenthoods
+          WHERE person_id = #{sanitize(parent_id)}
+        ) as s1 on s1.child_id = children.id")
+      .where("s1.child_id is null")
+      .order(:first_name, :last_name)
+      .uniq
+  }
+
   def name
     "#{first_name} #{last_name}"
   end
diff --git a/app/models/person.rb b/app/models/person.rb
index 8ea50a6..f804d1e 100644
--- a/app/models/person.rb
+++ b/app/models/person.rb
@@ -1,10 +1,11 @@
 class Person < ActiveRecord::Base
   has_many :parenthoods
   has_many :children, through: :parenthoods
-  accepts_nested_attributes_for :children
+  accepts_nested_attributes_for :children, reject_if: :all_blank
 
   validates :first_name, presence: true
   validates :last_name, presence: true
+  validates :phone, presence: true
 
   scope :with_name, lambda { |name|
     where("concat(first_name, ' ', last_name) RLIKE ?", name)
diff --git a/app/views/parents/index.html.haml b/app/views/parents/index.html.haml
index 0a182a0..a7af5d2 100644
--- a/app/views/parents/index.html.haml
+++ b/app/views/parents/index.html.haml
@@ -2,7 +2,9 @@
 
 - @parents.each do |parent|
   %ul
-    %li #{parent.name} #{page_link(parent)}
+    %li
+      = link_to parent.name, parent_path(parent)
+      = page_link(parent)
     %li= number_to_phone parent.phone
     %li= mail_to parent.email
     %li Children:
diff --git a/app/views/parents/new.html.haml b/app/views/parents/new.html.haml
index 708381e..5381c12 100644
--- a/app/views/parents/new.html.haml
+++ b/app/views/parents/new.html.haml
@@ -1,6 +1,12 @@
 %h2 Add a New Parent
 
-= form_for :parent do |f|
+- if @parent.errors.full_messages.any?
+  .errors
+    %h1 Uh oh!
+    - @parent.errors.full_messages.each do |e|
+      %p= e
+
+= form_for @parent, as: :parent, url: add_parent_path do |f|
   = f.label :first_name
   = f.text_field :first_name
 
@@ -14,12 +20,11 @@
   = f.email_field :email
 
   %h3 Children:
-
-  = fields_for :child do |child|
-    = child.label :first_name
-    = child.text_field :first_name
-
-    = child.label :last_name
-    = child.text_field :last_name
+  = f.fields_for :children, @parent.children do |c|
+    %fieldset
+      = c.label :first_name
+      = c.text_field :first_name
+      = c.label :last_name
+      = c.text_field :last_name
 
   = f.submit
diff --git a/app/views/parents/show.html.haml b/app/views/parents/show.html.haml
index 878e1b1..47f066f 100644
--- a/app/views/parents/show.html.haml
+++ b/app/views/parents/show.html.haml
@@ -1,2 +1,21 @@
-%h2 Parent
-= raw(ap @parent)
+%h2= @parent.name
+%p= link_to 'edit', edit_parent_path(@parent)
+%p Email: #{mail_to(@parent.email, nil, encode: 'hex')}
+%p Phone: #{number_to_phone @parent.phone} #{page_link(@parent)}
+
+- unless @parent.children.empty?
+  %p Children:
+  %ul
+    - @parent.children.each do |child|
+      %li
+        = child.name
+        = link_to 'remove', del_parenthood_path(@parent, child), {method: :delete}
+
+%p Add Child:
+:ruby
+  select_options = options_from_collection_for_select(@more_children, :id, :name)
+  html_options = {
+    include_blank: false,
+    prompt: 'Add a child to parent'
+  }
+= select_tag(:child, select_options, html_options)
diff --git a/config/routes.rb b/config/routes.rb
index b62b2b3..fce61bc 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -2,9 +2,13 @@ Rails.application.routes.draw do
   get 'parents', to: 'parents#index', as: :list_parents
   get 'parents/new', to: 'parents#new', as: :new_parent
   post 'parents/new', to: 'parents#add', as: :add_parent
+  get 'parents/edit/:id', to: 'parents#edit', as: :edit_parent
   get 'parents/:id', to: 'parents#show', as: :parent
   post 'parents/:id', to: 'parents#update', as: :update_parent
 
+  post 'parenthood/:parent/:child', to: 'relationships#add_child', as: :add_parenthood
+  delete 'parenthood/:parent/:child', to: 'relationships#del_child', as: :del_parenthood
+
   get 'children', to: 'children#index', as: :list_children
   get 'children/lookup', to: 'children#lookup', as: :lookup_child