Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
  • 5 commits
  • 26 files changed
  • 0 comments
  • 2 contributors

Showing 26 changed files with 295 additions and 64 deletions. Show diff stats Hide diff stats

  1. +1 2  Gemfile
  2. +7 2 Gemfile.lock
  3. +1 0  app/assets/javascripts/application.js
  4. +5 2 app/assets/javascripts/legs.js.coffee
  5. +71 0 app/assets/javascripts/nested_form.js
  6. +3 0  app/assets/javascripts/trips.js.coffee
  7. +0 16 app/assets/stylesheets/legs.css.scss
  8. +3 0  app/assets/stylesheets/trips.css.scss
  9. +68 5 app/controllers/trips_controller.rb
  10. +2 0  app/helpers/trips_helper.rb
  11. +1 0  app/models/leg.rb
  12. +2 3 app/models/trip.rb
  13. +4 0 app/views/layouts/application.html.erb
  14. +21 16 app/views/trips/_form.html.erb
  15. +0 2  app/views/trips/create.html.erb
  16. +6 2 app/views/trips/edit.html.erb
  17. +25 2 app/views/trips/index.html.erb
  18. +4 1 app/views/trips/new.html.erb
  19. +15 0 app/views/trips/show.html.erb
  20. +0 2  app/views/trips/update.html.erb
  21. +1 1  config/routes.rb
  22. +0 6 db/migrate/20120301214027_add_trip_id_to_legs.rb
  23. +1 0  db/migrate/{20120301213432_create_trips.rb → 20120308215936_create_trips.rb}
  24. +1 2  db/schema.rb
  25. +49 0 test/functional/trips_controller_test.rb
  26. +4 0 test/unit/helpers/trips_helper_test.rb
3  Gemfile
@@ -4,7 +4,6 @@ gem 'rails', '3.2.0'
4 4
5 5 # Bundle edge Rails instead:
6 6 # gem 'rails', :git => 'git://github.com/rails/rails.git'
7   -
8 7 gem 'sqlite3'
9 8
10 9 gem 'json'
@@ -22,7 +21,7 @@ group :assets do
22 21 end
23 22
24 23 gem 'jquery-rails'
25   -gem "nested_form"
  24 +gem "nested_form" , :git => "https://github.com/ryanb/nested_form.git"
26 25
27 26 # To use ActiveModel has_secure_password
28 27 # gem 'bcrypt-ruby', '~> 3.0.0'
9 Gemfile.lock
... ... @@ -1,3 +1,9 @@
  1 +GIT
  2 + remote: https://github.com/ryanb/nested_form.git
  3 + revision: 486e0f0e93f3ca455d5d0fc7869053257b6afce2
  4 + specs:
  5 + nested_form (0.2.0)
  6 +
1 7 GEM
2 8 remote: https://rubygems.org/
3 9 specs:
@@ -53,7 +59,6 @@ GEM
53 59 treetop (~> 1.4.8)
54 60 mime-types (1.17.2)
55 61 multi_json (1.1.0)
56   - nested_form (0.2.0)
57 62 polyglot (0.3.3)
58 63 rack (1.4.1)
59 64 rack-cache (1.1)
@@ -107,7 +112,7 @@ DEPENDENCIES
107 112 coffee-rails (~> 3.2.1)
108 113 jquery-rails
109 114 json
110   - nested_form
  115 + nested_form!
111 116 rails (= 3.2.0)
112 117 sass-rails (~> 3.2.3)
113 118 sqlite3
1  app/assets/javascripts/application.js
@@ -13,5 +13,6 @@
13 13 //= require jquery
14 14 //= require jquery_ujs
15 15 //= require_tree .
  16 +//= require nested_form
16 17
17 18
7 app/assets/javascripts/legs.js.coffee
@@ -2,9 +2,12 @@
2 2 # All this logic will automatically be available in application.js.
3 3 # You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
4 4 $ ->
5   - changeDiv = ->
  5 + trHighlight = ->
6 6 $("table tr").removeClass 'active'
7 7 $(@).addClass 'active'
  8 + notrHighlight = ->
  9 + $("table tr").removeClass 'active'
8 10
9   - $("table tr").mouseenter changeDiv
  11 + $("table tr").mouseenter trHighlight
  12 + $('table').mouseleave notrHighlight
10 13
71 app/assets/javascripts/nested_form.js
... ... @@ -0,0 +1,71 @@
  1 +jQuery(function($) {
  2 + window.NestedFormEvents = function() {
  3 + this.addFields = $.proxy(this.addFields, this);
  4 + this.removeFields = $.proxy(this.removeFields, this);
  5 + };
  6 +
  7 + NestedFormEvents.prototype = {
  8 + addFields: function(e) {
  9 + // Setup
  10 + var link = e.currentTarget;
  11 + var assoc = $(link).attr('data-association'); // Name of child
  12 + var content = $('#' + assoc + '_fields_blueprint').html(); // Fields template
  13 +
  14 + // Make the context correct by replacing new_<parents> with the generated ID
  15 + // of each of the parent objects
  16 + var context = ($(link).closest('.fields').find('input:first').attr('name') || '').replace(new RegExp('\[[a-z]+\]$'), '');
  17 +
  18 + // context will be something like this for a brand new form:
  19 + // project[tasks_attributes][new_1255929127459][assignments_attributes][new_1255929128105]
  20 + // or for an edit form:
  21 + // project[tasks_attributes][0][assignments_attributes][1]
  22 + if (context) {
  23 + var parentNames = context.match(/[a-z_]+_attributes/g) || [];
  24 + var parentIds = context.match(/(new_)?[0-9]+/g) || [];
  25 +
  26 + for(var i = 0; i < parentNames.length; i++) {
  27 + if(parentIds[i]) {
  28 + content = content.replace(
  29 + new RegExp('(_' + parentNames[i] + ')_.+?_', 'g'),
  30 + '$1_' + parentIds[i] + '_');
  31 +
  32 + content = content.replace(
  33 + new RegExp('(\\[' + parentNames[i] + '\\])\\[.+?\\]', 'g'),
  34 + '$1[' + parentIds[i] + ']');
  35 + }
  36 + }
  37 + }
  38 +
  39 + // Make a unique ID for the new child
  40 + var regexp = new RegExp('new_' + assoc, 'g');
  41 + var new_id = new Date().getTime();
  42 + content = content.replace(regexp, "new_" + new_id);
  43 +
  44 + var field = this.insertFields(content, assoc, link);
  45 + $(link).closest("form")
  46 + .trigger({ type: 'nested:fieldAdded', field: field })
  47 + .trigger({ type: 'nested:fieldAdded:' + assoc, field: field });
  48 + return false;
  49 + },
  50 + insertFields: function(content, assoc, link) {
  51 + return $(content).insertBefore(link);
  52 + },
  53 + removeFields: function(e) {
  54 + var link = e.currentTarget;
  55 + var hiddenField = $(link).prev('input[type=hidden]');
  56 + hiddenField.val('1');
  57 + // if (hiddenField) {
  58 + // $(link).v
  59 + // hiddenField.value = '1';
  60 + // }
  61 + var field = $(link).closest('.fields');
  62 + field.hide();
  63 + $(link).closest("form").trigger({ type: 'nested:fieldRemoved', field: field });
  64 + return false;
  65 + }
  66 + };
  67 +
  68 + window.nestedFormEvents = new NestedFormEvents();
  69 + $('form a.add_nested_fields').live('click', nestedFormEvents.addFields);
  70 + $('form a.remove_nested_fields').live('click', nestedFormEvents.removeFields);
  71 +});
3  app/assets/javascripts/trips.js.coffee
... ... @@ -0,0 +1,3 @@
  1 +# Place all the behaviors and hooks related to the matching controller here.
  2 +# All this logic will automatically be available in application.js.
  3 +# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
16 app/assets/stylesheets/legs.css.scss
... ... @@ -1,16 +0,0 @@
1   -// Place all the styles related to the legs controller here.
2   -// They will automatically be included in application.css.
3   -// You can use Sass (SCSS) here: http://sass-lang.com/
4   -
5   -table {
6   - background-color:#87CEEB;
7   - font-size:1.5em;
8   - font-family:Sans-serif;
9   -}
10   -table, th, td {
11   - border: 2px solid white;
12   -}
13   -.active {
14   - background-color:#FFFFFF;
15   - font-weight:bold;
16   -}
3  app/assets/stylesheets/trips.css.scss
... ... @@ -0,0 +1,3 @@
  1 +// Place all the styles related to the trips controller here.
  2 +// They will automatically be included in application.css.
  3 +// You can use Sass (SCSS) here: http://sass-lang.com/
73 app/controllers/trips_controller.rb
... ... @@ -1,20 +1,83 @@
1 1 class TripsController < ApplicationController
2   -
  2 + # GET /trips
  3 + # GET /trips.json
3 4 def index
4   -
  5 + @trips = Trip.all
  6 +
  7 + respond_to do |format|
  8 + format.html # index.html.erb
  9 + format.json { render json: @trips }
  10 + end
  11 + end
  12 +
  13 + # GET /trips/1
  14 + # GET /trips/1.json
  15 + def show
  16 + @trip = Trip.find(params[:id])
  17 +
  18 + respond_to do |format|
  19 + format.html # show.html.erb
  20 + format.json { render json: @trip }
  21 + end
5 22 end
6 23
  24 + # GET /trips/new
  25 + # GET /trips/new.json
7 26 def new
8 27 @trip = Trip.new
9   - @trip.legs.build
10   - end
11 28
12   - def create
  29 + respond_to do |format|
  30 + format.html # new.html.erb
  31 + format.json { render json: @trip }
  32 + end
13 33 end
14 34
  35 + # GET /trips/1/edit
15 36 def edit
  37 + @trip = Trip.find(params[:id])
  38 + end
  39 +
  40 + # POST /trips
  41 + # POST /trips.json
  42 + def create
  43 + @trip = Trip.new(params[:trip])
  44 +
  45 + respond_to do |format|
  46 + if @trip.save
  47 + format.html { redirect_to @trip, notice: 'Trip was successfully created.' }
  48 + format.json { render json: @trip, status: :created, location: @trip }
  49 + else
  50 + format.html { render action: "new" }
  51 + format.json { render json: @trip.errors, status: :unprocessable_entity }
  52 + end
  53 + end
16 54 end
17 55
  56 + # PUT /trips/1
  57 + # PUT /trips/1.json
18 58 def update
  59 + @trip = Trip.find(params[:id])
  60 +
  61 + respond_to do |format|
  62 + if @trip.update_attributes(params[:trip])
  63 + format.html { redirect_to @trip, notice: 'Trip was successfully updated.' }
  64 + format.json { head :no_content }
  65 + else
  66 + format.html { render action: "edit" }
  67 + format.json { render json: @trip.errors, status: :unprocessable_entity }
  68 + end
  69 + end
  70 + end
  71 +
  72 + # DELETE /trips/1
  73 + # DELETE /trips/1.json
  74 + def destroy
  75 + @trip = Trip.find(params[:id])
  76 + @trip.destroy
  77 +
  78 + respond_to do |format|
  79 + format.html { redirect_to trips_url }
  80 + format.json { head :no_content }
  81 + end
19 82 end
20 83 end
2  app/helpers/trips_helper.rb
... ... @@ -0,0 +1,2 @@
  1 +module TripsHelper
  2 +end
1  app/models/leg.rb
@@ -2,6 +2,7 @@ class Leg < ActiveRecord::Base
2 2 validates_presence_of :location, :on => :create, :message => "can't be blank"
3 3 validates_presence_of :depart_arrive, :on => :create, :message => "can't be blank"
4 4 validate :depart_or_arrive, :on => :create
  5 + has_one :trip
5 6 def depart_or_arrive
6 7 if depart_arrive_type != 'Departure' && depart_arrive_type != 'Arrival'
7 8 errors.add(:depart_arrive_type, "must be either 'Depart' or 'Arrive'")
5 app/models/trip.rb
... ... @@ -1,5 +1,4 @@
1 1 class Trip < ActiveRecord::Base
2   - has_many :legs
3   -
4   - accepts_nested_attributes_for :legs
  2 + has_many :legs, :dependent => :destroy
  3 + accepts_nested_attributes_for :legs, :reject_if => lambda { |a| a[:content].blank? }, :allow_destroy => true
5 4 end
4 app/views/layouts/application.html.erb
@@ -5,7 +5,11 @@
5 5 <%= stylesheet_link_tag "application", :media => "all" %>
6 6 <%= javascript_include_tag "application" %>
7 7
  8 +
  9 +
  10 +
8 11 <%= csrf_meta_tags %>
  12 +
9 13 </head>
10 14 <body>
11 15
37 app/views/trips/_form.html.erb
... ... @@ -1,10 +1,10 @@
1   -<%= form_for(@trip) do |f| %>
  1 +<%= nested_form_for @trip do |f| %>
2 2 <% if @trip.errors.any? %>
3 3 <div id="error_explanation">
4   - <h2><%= pluralize(@leg.errors.count, "error") %> prohibited this leg from being saved:</h2>
  4 + <h2><%= pluralize(@trip.errors.count, "error") %> prohibited this trip from being saved:</h2>
5 5
6 6 <ul>
7   - <% @leg.errors.full_messages.each do |msg| %>
  7 + <% @trip.errors.full_messages.each do |msg| %>
8 8 <li><%= msg %></li>
9 9 <% end %>
10 10 </ul>
@@ -13,23 +13,28 @@
13 13
14 14 <div class="field">
15 15 <%= f.label :name %><br />
16   - <%= f.text_field :name, :size=>30 %>
  16 + <%= f.text_field :name %>
17 17 </div>
18   - <%= f.fields_for :legs do |l| %>
19 18 <div class="field">
20   - <%= l.label :location %><br />
21   - <%= l.text_field :location %>
22   - </div>
23   - <div class="field">
24   - <%= l.label :depart_arrive_type %><br />
25   - <%= l.select :depart_arrive_type, ["Departure", "Arrival"] %>
26   -
27   - </div>
28   - <div class="field">
29   - <%= l.label :depart_arrive %><br />
30   - <%= l.datetime_select :depart_arrive %>
  19 + <%= f.label :email %><br />
  20 + <%= f.text_field :email %>
31 21 </div>
  22 + <div class="field">
  23 + <%= f.fields_for :legs do |legs_form| %>
  24 + <%= legs_form.label :location, "Location:" %><br />
  25 + <%= legs_form.text_field :location %><br />
  26 +
  27 + <%= legs_form.label :depart_arrive_type, "Departure or Arrival?" %><br />
  28 + <%= legs_form.select :depart_arrive_type, ["Departure", "Arrival"] %><br />
  29 +
  30 + <%= legs_form.label :depart_arrive, "Departure/Arrival Date:" %><br />
  31 + <%= legs_form.datetime_select :depart_arrive %> <br />
  32 + <%= legs_form.label :details, "Leg details:" %> <br />
  33 + <%= legs_form.text_field :details %>
  34 + <%= legs_form.link_to_remove "Remove Leg" %>
32 35 <% end %>
  36 + <p><%= f.link_to_add "Add a Leg", :legs %></p>
  37 + </div>
33 38 <div class="actions">
34 39 <%= f.submit %>
35 40 </div>
2  app/views/trips/create.html.erb
... ... @@ -1,2 +0,0 @@
1   -<h1>Trip#create</h1>
2   -<p>Find me in app/views/trip/create.html.erb</p>
8 app/views/trips/edit.html.erb
... ... @@ -1,2 +1,6 @@
1   -<h1>Trip#edit</h1>
2   -<p>Find me in app/views/trip/edit.html.erb</p>
  1 +<h1>Editing trip</h1>
  2 +
  3 +<%= render 'form' %>
  4 +
  5 +<%= link_to 'Show', @trip %> |
  6 +<%= link_to 'Back', trips_path %>
27 app/views/trips/index.html.erb
... ... @@ -1,2 +1,25 @@
1   -<h1>All Trips</h1>
2   -<p>Find me in app/views/trip/index.html.erb</p>
  1 +<h1>Listing trips</h1>
  2 +
  3 +<table>
  4 + <tr>
  5 + <th>Name</th>
  6 + <th>Email</th>
  7 + <th></th>
  8 + <th></th>
  9 + <th></th>
  10 + </tr>
  11 +
  12 +<% @trips.each do |trip| %>
  13 + <tr>
  14 + <td><%= trip.name %></td>
  15 + <td><%= trip.email %></td>
  16 + <td><%= link_to 'Show', trip %></td>
  17 + <td><%= link_to 'Edit', edit_trip_path(trip) %></td>
  18 + <td><%= link_to 'Destroy', trip, confirm: 'Are you sure?', method: :delete %></td>
  19 + </tr>
  20 +<% end %>
  21 +</table>
  22 +
  23 +<br />
  24 +
  25 +<%= link_to 'New Trip', new_trip_path %>
5 app/views/trips/new.html.erb
... ... @@ -1,2 +1,5 @@
1 1 <h1>New Trip</h1>
2   -<%= render "form" %>
  2 +
  3 +<%= render 'form' %>
  4 +
  5 +<%= link_to 'Back', trips_path %>
15 app/views/trips/show.html.erb
... ... @@ -0,0 +1,15 @@
  1 +<p id="notice"><%= notice %></p>
  2 +
  3 +<p>
  4 + <b>Name:</b>
  5 + <%= @trip.name %>
  6 +</p>
  7 +
  8 +<p>
  9 + <b>Email:</b>
  10 + <%= @trip.email %>
  11 +</p>
  12 +
  13 +
  14 +<%= link_to 'Edit', edit_trip_path(@trip) %> |
  15 +<%= link_to 'Back', trips_path %>
2  app/views/trips/update.html.erb
... ... @@ -1,2 +0,0 @@
1   -<h1>Trip#update</h1>
2   -<p>Find me in app/views/trip/update.html.erb</p>
2  config/routes.rb
... ... @@ -1,7 +1,7 @@
1 1 Tripd::Application.routes.draw do
2 2
3   -
4 3 resources :trips
  4 +
5 5 resources :legs
6 6
7 7 # The priority is based upon order of creation:
6 db/migrate/20120301214027_add_trip_id_to_legs.rb
... ... @@ -1,6 +0,0 @@
1   -class AddTripIdToLegs < ActiveRecord::Migration
2   - def change
3   - add_column :legs, :trip_id, :integer
4   -
5   - end
6   -end
1  db/migrate/20120301213432_create_trips.rb → db/migrate/20120308215936_create_trips.rb
@@ -3,6 +3,7 @@ def change
3 3 create_table :trips do |t|
4 4 t.string :name
5 5 t.string :email
  6 +
6 7 t.timestamps
7 8 end
8 9 end
3  db/schema.rb
@@ -11,7 +11,7 @@
11 11 #
12 12 # It's strongly recommended to check this file into your version control system.
13 13
14   -ActiveRecord::Schema.define(:version => 20120301214027) do
  14 +ActiveRecord::Schema.define(:version => 20120308213926) do
15 15
16 16 create_table "legs", :force => true do |t|
17 17 t.string "location"
@@ -20,7 +20,6 @@
20 20 t.text "details"
21 21 t.datetime "created_at", :null => false
22 22 t.datetime "updated_at", :null => false
23   - t.integer "trip_id"
24 23 end
25 24
26 25 create_table "trips", :force => true do |t|
49 test/functional/trips_controller_test.rb
... ... @@ -0,0 +1,49 @@
  1 +require 'test_helper'
  2 +
  3 +class TripsControllerTest < ActionController::TestCase
  4 + setup do
  5 + @trip = trips(:one)
  6 + end
  7 +
  8 + test "should get index" do
  9 + get :index
  10 + assert_response :success
  11 + assert_not_nil assigns(:trips)
  12 + end
  13 +
  14 + test "should get new" do
  15 + get :new
  16 + assert_response :success
  17 + end
  18 +
  19 + test "should create trip" do
  20 + assert_difference('Trip.count') do
  21 + post :create, trip: @trip.attributes
  22 + end
  23 +
  24 + assert_redirected_to trip_path(assigns(:trip))
  25 + end
  26 +
  27 + test "should show trip" do
  28 + get :show, id: @trip
  29 + assert_response :success
  30 + end
  31 +
  32 + test "should get edit" do
  33 + get :edit, id: @trip
  34 + assert_response :success
  35 + end
  36 +
  37 + test "should update trip" do
  38 + put :update, id: @trip, trip: @trip.attributes
  39 + assert_redirected_to trip_path(assigns(:trip))
  40 + end
  41 +
  42 + test "should destroy trip" do
  43 + assert_difference('Trip.count', -1) do
  44 + delete :destroy, id: @trip
  45 + end
  46 +
  47 + assert_redirected_to trips_path
  48 + end
  49 +end
4 test/unit/helpers/trips_helper_test.rb
... ... @@ -0,0 +1,4 @@
  1 +require 'test_helper'
  2 +
  3 +class TripsHelperTest < ActionView::TestCase
  4 +end

No commit comments for this range

Something went wrong with that request. Please try again.