├── .gitignore
├── .rspec
├── .rvmrc
├── .travis.yml
├── CHANGELOG.rdoc
├── CONTRIBUTING.md
├── Gemfile
├── LICENSE
├── README.md
├── Rakefile
├── gemfiles
├── Gemfile.base
├── Gemfile.rails3_0
└── Gemfile.rails3_1
├── lib
├── generators
│ └── nested_form
│ │ └── install_generator.rb
├── nested_form.rb
└── nested_form
│ ├── builder_mixin.rb
│ ├── builders.rb
│ ├── engine.rb
│ └── view_helper.rb
├── nested_form.gemspec
├── spec
├── dummy
│ ├── Rakefile
│ ├── app
│ │ ├── assets
│ │ │ ├── javascripts
│ │ │ │ ├── application.js
│ │ │ │ ├── jquery.js
│ │ │ │ ├── jquery_events_test.js
│ │ │ │ ├── jquery_nested_form.js
│ │ │ │ ├── projects.js
│ │ │ │ ├── prototype.js
│ │ │ │ ├── prototype_events_test.js
│ │ │ │ └── prototype_nested_form.js
│ │ │ └── stylesheets
│ │ │ │ ├── application.css
│ │ │ │ ├── companies.css
│ │ │ │ └── projects.css
│ │ ├── controllers
│ │ │ ├── application_controller.rb
│ │ │ ├── companies_controller.rb
│ │ │ └── projects_controller.rb
│ │ ├── helpers
│ │ │ ├── application_helper.rb
│ │ │ └── projects_helper.rb
│ │ ├── mailers
│ │ │ └── .gitkeep
│ │ ├── models
│ │ │ ├── .gitkeep
│ │ │ ├── company.rb
│ │ │ ├── milestone.rb
│ │ │ ├── project.rb
│ │ │ ├── project_task.rb
│ │ │ └── task.rb
│ │ └── views
│ │ │ ├── companies
│ │ │ └── new.html.erb
│ │ │ ├── layouts
│ │ │ └── application.html.erb
│ │ │ └── projects
│ │ │ ├── new.html.erb
│ │ │ └── without_intermediate_inputs.html.erb
│ ├── config.ru
│ ├── config
│ │ ├── application.rb
│ │ ├── boot.rb
│ │ ├── database.yml
│ │ ├── environment.rb
│ │ ├── environments
│ │ │ ├── development.rb
│ │ │ ├── production.rb
│ │ │ └── test.rb
│ │ ├── initializers
│ │ │ ├── backtrace_silencers.rb
│ │ │ ├── inflections.rb
│ │ │ ├── mime_types.rb
│ │ │ ├── secret_token.rb
│ │ │ ├── session_store.rb
│ │ │ └── wrap_parameters.rb
│ │ ├── locales
│ │ │ └── en.yml
│ │ └── routes.rb
│ ├── db
│ │ ├── migrate
│ │ │ ├── 20110710143903_initial_tables.rb
│ │ │ ├── 20120819164528_add_association_with_class_name.rb
│ │ │ └── 20130203095901_create_company.rb
│ │ └── schema.rb
│ ├── public
│ │ ├── 404.html
│ │ ├── 422.html
│ │ ├── 500.html
│ │ ├── favicon.ico
│ │ └── javascripts
│ ├── script
│ │ └── rails
│ ├── test
│ │ ├── functional
│ │ │ └── projects_controller_test.rb
│ │ └── unit
│ │ │ └── helpers
│ │ │ └── projects_helper_test.rb
│ └── tmp
│ │ └── cache
│ │ └── .gitkeep
├── events_spec.rb
├── form_spec.rb
├── nested_form
│ ├── builder_spec.rb
│ └── view_helper_spec.rb
└── spec_helper.rb
└── vendor
└── assets
└── javascripts
├── jquery_nested_form.js
└── prototype_nested_form.js
/.gitignore:
--------------------------------------------------------------------------------
1 | *.swp
2 | **/*.swp
3 | *.gem
4 | Gemfile.lock
5 | .bundle
6 | log
7 | gemfiles/*.lock
8 | spec/dummy/tmp/
9 | spec/dummy/db/*.sqlite3
10 | .rbx
11 |
--------------------------------------------------------------------------------
/.rspec:
--------------------------------------------------------------------------------
1 | --color
2 |
--------------------------------------------------------------------------------
/.rvmrc:
--------------------------------------------------------------------------------
1 | rvm use 1.9.2@nested_form --create
2 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: ruby
2 | rvm:
3 | - 1.8.7
4 | - 1.9.3
5 | - jruby-18mode
6 | - jruby-19mode
7 | - rbx-18mode
8 | - rbx-19mode
9 | jdk:
10 | - openjdk6
11 | gemfile:
12 | - Gemfile
13 | - gemfiles/Gemfile.rails3_1
14 | - gemfiles/Gemfile.rails3_0
15 | before_script: "sh -c 'cd spec/dummy && rake db:migrate RAILS_ENV=test'"
16 | script: "xvfb-run rake"
17 | notifications:
18 | email:
19 | recipients:
20 | - just.lest@gmail.com
21 |
--------------------------------------------------------------------------------
/CHANGELOG.rdoc:
--------------------------------------------------------------------------------
1 | 0.3.2 (April 5, 2013)
2 |
3 | * Render blueprints inside form (thanks taavo)
4 |
5 | * Make generated ids easily overridable in jQuery version (thanks ghostganz)
6 |
7 | * Support `nested_wrapper` option as an alternative to `wrapper` option in
8 | order to maintain compatibility with `simple_fields_for` helper (#219)
9 |
10 | * Allow DOM target to be specified when adding new nested form elements
11 | (thanks mhuggins)
12 |
13 | * Fix "has_one => has_many => has_many" name generation (thanks kevinrood and
14 | basvanwesting)
15 |
16 | 0.3.1 (November 5, 2012)
17 |
18 | * Raise ArgumentError when accepts_nested_attributes_for is missing
19 |
20 | * Fix wrapper element disabling feature (#202 and #214)
21 |
22 | 0.3.0 (October 23, 2012)
23 |
24 | * Fix issue when deeply nested and first level only has a select input (thanks eric88)
25 |
26 | * Fix context getting for input names with an underscore (thanks kevinrood)
27 |
28 | * Add option to toggle wrapper div behavior with wrapper option in fields_for helper
29 |
30 | * Ability to set object for blueprint using model_object option in link_to_add helper (thanks Baltazore)
31 |
32 | * Support for FormtasticBootstrapBuilder (thanks rvanlieshout)
33 |
34 | * Store blueprint html in data-blueprint attribute
35 |
36 | * Add the marked_for_destruction class on the div if the object is marked for destruction
37 |
38 | * Add parent association name to the blueprint div id
39 |
40 | 0.2.3 (August 23, 2012)
41 |
42 | * Fix selector for deeply nested forms (thanks groe)
43 |
44 | * Fix association detection in #link_to remove (thanks nashbridges)
45 |
46 | * Add nested:fieldRemoved:type event (thanks nashbridges)
47 |
48 | * Add events for Prototype (thanks nashbridges)
49 |
50 | * Element.up() is the proper Prototype counter part to jQuery's closest() (thanks clemens)
51 |
52 | 0.2.2 (July 9, 2012)
53 |
54 | * Make deeply-nested form working in jruby and rubinius
55 |
56 | * Revert the "context" selector changes from 0.2.1 in order to work with jQuery 1.7.2
57 |
58 | 0.2.1 (June 4, 2012)
59 |
60 | * Added Travis integration (thanks fxposter)
61 |
62 | * Make the "context" selector stricter, to work with deeply-nested forms. (thanks groe and nickhoffman)
63 |
64 | * Include vendor folder in the gem for Rails 3.1 asset support (thanks dmarkow)
65 |
66 |
67 | 0.2.0 (February 7, 2012)
68 |
69 | * Integration tests (thanks fxposter) - issue #58
70 |
71 | * Improved simple_form and 3.1 support (thanks fxposter)
72 |
73 | * nested:fieldAdded event includes the newly added field (thanks harrigan)
74 |
75 | * other minor bug fixes
76 |
77 |
78 | 0.1.1 (April 23, 2011)
79 |
80 | * Support HTML options and block in add/remove link - issue #31
81 |
82 | * Added new RegEx to generate new objects IDs correctly - issue #26 and issue #30
83 |
84 |
85 | 0.1.0 (March 26, 2011)
86 |
87 | * Prefix new records with "new_" so there's no possible conflict with existing records - issue #21
88 |
89 | * Add support for _fields partial if no block is passed in to fields_for
90 |
91 | * Use the $-jquery-function only inside the jQuery scope (thanks nhocki)
92 |
93 | * Triggers nested:fieldAdded and nested:fieldRemoved events (thanks pirelenito)
94 |
95 | * Fixed JavaScript bug for nested attributes in has_one association (thanks pirelenito)
96 |
97 |
98 | 0.0.0 (February 17, 2011)
99 |
100 | * Initial release
101 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ### Please read before contributing
2 |
3 | 1) If you have any questions about NestedForm, search the [Wiki](https://github.com/ryanb/nested_form/wiki) or [Stack Overflow](http://stackoverflow.com). Do not post questions here.
4 |
5 | 2) If you find a security bug, **DO NOT** submit an issue here. Please send an e-mail to [just.lest@gmail.com](mailto:just.lest@gmail.com) instead.
6 |
7 | 3) Do a small search on the issues tracker before submitting your issue to see if it was already reported / fixed. In case it was not, create your report including Rails and NestedForm versions. If you are getting exceptions, please include the full backtrace into a gist.
8 |
9 | That's it! The more information you give, the more easy it becomes for us to track it down and fix it. Ideal scenario would be adding the issue to NestedForm test suite or to a sample application.
10 |
11 | Thanks!
12 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | gemspec :path => '.'
2 |
3 | instance_eval File.read(File.expand_path('../gemfiles/Gemfile.base', __FILE__))
4 |
5 | gem 'rails', '~> 3.2.0'
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2011 Ryan Bates
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Unmaintained
2 |
3 | The Nested Form gem is **no longer maintained**. Feel free to fork this project.
4 |
5 | # Nested Form
6 |
7 | [](http://travis-ci.org/ryanb/nested_form)
8 |
9 | This is a Rails gem for conveniently manage multiple nested models in a single form. It does so in an unobtrusive way through jQuery or Prototype.
10 |
11 | This gem only works with Rails 3. See the [rails2 branch](https://github.com/ryanb/nested_form/tree/rails2) for a plugin to work in Rails 2.
12 |
13 | An example project showing how this works is available in the [complex-nested-forms/nested_form branch](https://github.com/ryanb/complex-form-examples/tree/nested_form).
14 |
15 |
16 | ## Setup
17 |
18 | Add it to your Gemfile then run `bundle` to install it.
19 |
20 | ```ruby
21 | gem "nested_form"
22 | ```
23 |
24 | And then add it to the Asset Pipeline in the application.js file:
25 |
26 | ```
27 | //= require jquery_nested_form
28 | ```
29 |
30 | ### Non Asset Pipeline Setup
31 |
32 | If you do not use the asset pipeline, run this generator to create the JavaScript file.
33 |
34 | ```
35 | rails g nested_form:install
36 | ```
37 |
38 | You can then include the generated JavaScript in your layout.
39 |
40 | ```erb
41 | <%= javascript_include_tag :defaults, "nested_form" %>
42 | ```
43 |
44 | ## Usage
45 |
46 | Imagine you have a `Project` model that `has_many :tasks`. To be able to use this gem, you'll need to add `accepts_nested_attributes_for :tasks` to your Project model. If you wish to allow the nested objects to be destroyed, then add the `:allow_destroy => true` option to that declaration. See the [accepts_nested_attributes_for documentation](http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html#method-i-accepts_nested_attributes_for) for details on all available options.
47 |
48 | This will create a `tasks_attributes=` method, so you may need to add it to the `attr_accessible` array (`attr_accessible :tasks_attributes`).
49 |
50 | Then use the `nested_form_for` helper method to enable the nesting.
51 |
52 | ```erb
53 | <%= nested_form_for @project do |f| %>
54 | ```
55 |
56 | You will then be able to use `link_to_add` and `link_to_remove` helper methods on the form builder in combination with fields_for to dynamically add/remove nested records.
57 |
58 | ```erb
59 | <%= f.fields_for :tasks do |task_form| %>
60 | <%= task_form.text_field :name %>
61 | <%= task_form.link_to_remove "Remove this task" %>
62 | <% end %>
63 |
<%= f.link_to_add "Add a task", :tasks %>
64 | ```
65 |
66 | In order to choose how to handle, after validation errors, fields that are
67 | marked for destruction, the `marked_for_destruction` class is added on the div
68 | if the object is marked for destruction.
69 |
70 | ## Strong Parameters
71 | For Rails 4 or people using the "strong_parameters" gem, here is an example:
72 |
73 | ```ruby
74 | params.require(:project).permit(:name, tasks_attributes: [:id, :name, :_destroy])
75 | ```
76 |
77 | The `:id` is to make sure you do not end up with a whole lot of tasks.
78 |
79 | The `:_destroy` must be there so that we can delete tasks.
80 |
81 | ## SimpleForm and Formtastic Support
82 |
83 | Use `simple_nested_form_for` or `semantic_nested_form_for` for SimpleForm and Formtastic support respectively.
84 |
85 |
86 | ## Partials
87 |
88 | It is often desirable to move the nested fields into a partial to keep things organized. If you don't supply a block to fields_for it will look for a partial and use that.
89 |
90 | ```erb
91 | <%= f.fields_for :tasks %>
92 | ```
93 |
94 | In this case it will look for a partial called "task_fields" and pass the form builder as an `f` variable to it.
95 |
96 |
97 | ## Specifying a Target for Nested Fields
98 |
99 | By default, `link_to_add` appends fields immediately before the link when
100 | clicked. This is not desirable when using a list or table, for example. In
101 | these situations, the "data-target" attribute can be used to specify where new
102 | fields should be inserted.
103 |
104 | ```erb
105 |
114 | ```
115 |
116 | Note that the `:data` option above only works in Rails 3.1+. For Rails 3.0 and
117 | below, the following syntax must be used.
118 |
119 | ```erb
120 |
<%= f.link_to_add "Add a task", :tasks, "data-target" => "#tasks" %>
121 | ```
122 |
123 |
124 | ## JavaScript events
125 |
126 | Sometimes you want to do some additional work after element was added or removed, but only
127 | after DOM was _really_ modified. In this case simply listening for click events on
128 | 'Add new'/'Remove' link won't reliably work, because your code and code that inserts/removes
129 | nested field will run concurrently.
130 |
131 | This problem can be solved, because after adding or removing the field a set of custom events
132 | is triggered on this field. Using form example from above, if you click on the "Add a task" link,
133 | `nested:fieldAdded` and `nested:fieldAdded:tasks` will be triggered, while
134 | `nested:fieldRemoved` and `nested:fieldRemoved:tasks` will be triggered if you click
135 | "Remove this task" then.
136 |
137 | These events bubble up the DOM tree, going through `form` element, until they reach the `document`.
138 | This allows you to listen for the event and trigger some action accordingly. Field element, upon
139 | which action was made, is passed along with the `event` object. In jQuery you can access it
140 | via `event.field`, in Prototype the same field will be in `event.memo.field`.
141 |
142 | For example, you have a date input in a nested field and you want to use jQuery datepicker
143 | for it. This is a bit tricky, because you have to activate datepicker after field was inserted.
144 |
145 | ### jQuery
146 |
147 | ```javascript
148 | $(document).on('nested:fieldAdded', function(event){
149 | // this field was just inserted into your form
150 | var field = event.field;
151 | // it's a jQuery object already! Now you can find date input
152 | var dateField = field.find('.date');
153 | // and activate datepicker on it
154 | dateField.datepicker();
155 | })
156 | ```
157 |
158 | ### Prototype
159 |
160 | ```javascript
161 | document.observe('nested:fieldAdded', function(event){
162 | var field = event.memo.field;
163 | // it's already extended by Prototype
164 | var dateField = field.down('.date');
165 | dateField.datepicker();
166 | })
167 | ```
168 |
169 | Second type of event (i.e. `nested:fieldAdded:tasks`) is useful then you have more than one type
170 | of nested fields on a form (i.e. tasks and milestones) and want to distinguish, which exactly
171 | was added/deleted.
172 |
173 | See also [how to limit max count of nested fields](https://github.com/ryanb/nested_form/wiki/How-to:-limit-max-count-of-nested-fields)
174 |
175 | ## Enhanced jQuery JavaScript template
176 |
177 | You can override default behavior of inserting new subforms into your form. For example:
178 |
179 | ```javascript
180 | window.nestedFormEvents.insertFields = function(content, assoc, link) {
181 | return $(link).closest('form').find(assoc + '_fields').append($(content));
182 | }
183 | ```
184 |
185 | ## Contributing
186 |
187 | If you have any issues with Nested Form not addressed above or in the [example project](https://github.com/ryanb/complex-form-examples/tree/nested_form), please add an [issue on GitHub](https://github.com/ryanb/nested_form/issues) or [fork the project](https://help.github.com/articles/fork-a-repo) and send a [pull request](https://help.github.com/articles/using-pull-requests). To run the specs:
188 |
189 | ```
190 | bundle install
191 | bundle exec rake spec:install
192 | bundle exec rake db:migrate
193 | bundle exec rake spec:all
194 | ```
195 |
196 | See available rake tasks using `bundle exec rake -T`.
197 |
198 | ## Special Thanks
199 |
200 | This gem was originally based on the solution by Tim Riley in his [complex-form-examples fork](https://github.com/timriley/complex-form-examples/tree/unobtrusive-jquery-deep-fix2).
201 |
202 | Thank you Andrew Manshin for the Rails 3 transition, [Andrea Singh](https://github.com/madebydna) for converting to a gem and [Peter Giacomo Lombardo](https://github.com/pglombardo) for Prototype support.
203 |
204 | Andrea also wrote a great [blog post](http://blog.madebydna.com/all/code/2010/10/07/dynamic-nested-froms-with-the-nested-form-gem.html) on the internal workings of this gem.
205 |
206 | Thanks [Pavel Forkert](https://github.com/fxposter) for the SimpleForm and Formtastic support.
207 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | require 'rubygems'
2 | require 'rake'
3 |
4 | begin
5 | require 'rspec/core/rake_task'
6 | desc "Run RSpec"
7 | RSpec::Core::RakeTask.new do |t|
8 | t.verbose = false
9 | end
10 | rescue LoadError
11 | puts "You should run rake spec:install in order to install all corresponding gems!"
12 | end
13 |
14 | task :default => :spec
15 |
16 | namespace :db do
17 | desc 'Prepare sqlite database'
18 | task :migrate do
19 | system 'cd spec/dummy && rake db:migrate RAILS_ENV=test && rake db:migrate RAILS_ENV=development'
20 | end
21 | end
22 |
23 | namespace :spec do
24 | desc 'Install gems from additional gemfiles'
25 | task :install do
26 | system 'bundle install'
27 | ENV.delete('GEM_HOME')
28 | ENV['BUNDLE_GEMFILE'] = File.expand_path('../gemfiles/Gemfile.rails3_1', __FILE__)
29 | system 'bundle install'
30 | ENV['BUNDLE_GEMFILE'] = File.expand_path('../gemfiles/Gemfile.rails3_0', __FILE__)
31 | system 'bundle install'
32 | end
33 |
34 | desc 'Run tests with Rails 3.1.x'
35 | task :rails3_1 do
36 | ENV.delete('GEM_HOME')
37 | ENV['BUNDLE_GEMFILE'] = File.expand_path('../gemfiles/Gemfile.rails3_1', __FILE__)
38 | Rake::Task["spec"].execute
39 | end
40 |
41 | desc 'Run tests with Rails 3.0.x'
42 | task :rails3_0 do
43 | ENV.delete('GEM_HOME')
44 | ENV['BUNDLE_GEMFILE'] = File.expand_path('../gemfiles/Gemfile.rails3_0', __FILE__)
45 | Rake::Task["spec"].execute
46 | end
47 |
48 | task :all do
49 | Rake::Task["spec"].execute
50 | Rake::Task["spec:rails3_1"].execute
51 | Rake::Task["spec:rails3_0"].execute
52 | end
53 | end
54 |
--------------------------------------------------------------------------------
/gemfiles/Gemfile.base:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 | gem 'activerecord-jdbcsqlite3-adapter', :platforms => :jruby
3 | gem "sqlite3", :platforms => :ruby
4 | gem "simple_form"
5 | gem "formtastic"
6 | gem "formtastic-bootstrap"
7 | gem "rake"
8 |
--------------------------------------------------------------------------------
/gemfiles/Gemfile.rails3_0:
--------------------------------------------------------------------------------
1 | gemspec :path => '../'
2 | instance_eval File.read(File.expand_path('../Gemfile.base', __FILE__))
3 | # forcing 3.0.20 (rather than 3.0.0) fixes a bug where bundle hangs
4 | # trying to fetch gems from github
5 | gem "rails", "~> 3.0.20"
6 |
--------------------------------------------------------------------------------
/gemfiles/Gemfile.rails3_1:
--------------------------------------------------------------------------------
1 | gemspec :path => '../'
2 | instance_eval File.read(File.expand_path('../Gemfile.base', __FILE__))
3 | gem "rails", "~> 3.1.0"
4 |
--------------------------------------------------------------------------------
/lib/generators/nested_form/install_generator.rb:
--------------------------------------------------------------------------------
1 | module NestedForm
2 | module Generators
3 | class InstallGenerator < Rails::Generators::Base
4 | def self.source_root
5 | File.expand_path('../../../../vendor/assets/javascripts', __FILE__)
6 | end
7 |
8 | def copy_jquery_file
9 | if File.exists?('public/javascripts/prototype.js')
10 | copy_file 'prototype_nested_form.js', 'public/javascripts/nested_form.js'
11 | else
12 | copy_file 'jquery_nested_form.js', 'public/javascripts/nested_form.js'
13 | end
14 | end
15 | end
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/lib/nested_form.rb:
--------------------------------------------------------------------------------
1 | require "nested_form/engine"
2 |
--------------------------------------------------------------------------------
/lib/nested_form/builder_mixin.rb:
--------------------------------------------------------------------------------
1 | module NestedForm
2 | module BuilderMixin
3 | # Adds a link to insert a new associated records. The first argument is the name of the link, the second is the name of the association.
4 | #
5 | # f.link_to_add("Add Task", :tasks)
6 | #
7 | # You can pass HTML options in a hash at the end and a block for the content.
8 | #
9 | # <%= f.link_to_add(:tasks, :class => "add_task", :href => new_task_path) do %>
10 | # Add Task
11 | # <% end %>
12 | #
13 | # You can also pass model_object option with an object for use in
14 | # the blueprint, e.g.:
15 | #
16 | # <%= f.link_to_add(:tasks, :model_object => Task.new(:name => 'Task')) %>
17 | #
18 | # See the README for more details on where to call this method.
19 | def link_to_add(*args, &block)
20 | options = args.extract_options!.symbolize_keys
21 | association = args.pop
22 |
23 | unless object.respond_to?("#{association}_attributes=")
24 | raise ArgumentError, "Invalid association. Make sure that accepts_nested_attributes_for is used for #{association.inspect} association."
25 | end
26 |
27 | model_object = options.delete(:model_object) do
28 | reflection = object.class.reflect_on_association(association)
29 | reflection.klass.new
30 | end
31 |
32 | options[:class] = [options[:class], "add_nested_fields"].compact.join(" ")
33 | options["data-association"] = association
34 | options["data-blueprint-id"] = fields_blueprint_id = fields_blueprint_id_for(association)
35 | args << (options.delete(:href) || "javascript:void(0)")
36 | args << options
37 |
38 | @fields ||= {}
39 | @template.after_nested_form(fields_blueprint_id) do
40 | blueprint = {:id => fields_blueprint_id, :style => 'display: none'}
41 | block, options = @fields[fields_blueprint_id].values_at(:block, :options)
42 | options[:child_index] = "new_#{association}"
43 | blueprint[:"data-blueprint"] = fields_for(association, model_object, options, &block).to_str
44 | @template.content_tag(:div, nil, blueprint)
45 | end
46 | @template.link_to(*args, &block)
47 | end
48 |
49 | # Adds a link to remove the associated record. The first argment is the name of the link.
50 | #
51 | # f.link_to_remove("Remove Task")
52 | #
53 | # You can pass HTML options in a hash at the end and a block for the content.
54 | #
55 | # <%= f.link_to_remove(:class => "remove_task", :href => "#") do %>
56 | # Remove Task
57 | # <% end %>
58 | #
59 | # See the README for more details on where to call this method.
60 | def link_to_remove(*args, &block)
61 | options = args.extract_options!.symbolize_keys
62 | options[:class] = [options[:class], "remove_nested_fields"].compact.join(" ")
63 |
64 | # Extracting "milestones" from "...[milestones_attributes][...]"
65 | md = object_name.to_s.match /(\w+)_attributes\](?:\[[\w\d]+\])?$/
66 | association = md && md[1]
67 | options["data-association"] = association
68 |
69 | args << (options.delete(:href) || "javascript:void(0)")
70 | args << options
71 | hidden_field(:_destroy) << @template.link_to(*args, &block)
72 | end
73 |
74 | def fields_for_with_nested_attributes(association_name, *args)
75 | # TODO Test this better
76 | block = args.pop || Proc.new { |fields| @template.render(:partial => "#{association_name.to_s.singularize}_fields", :locals => {:f => fields}) }
77 |
78 | options = args.dup.extract_options!
79 |
80 | # Rails 3.0.x
81 | if options.empty? && args[0].kind_of?(Array)
82 | options = args[0].dup.extract_options!
83 | end
84 |
85 | @fields ||= {}
86 | @fields[fields_blueprint_id_for(association_name)] = { :block => block, :options => options }
87 | super(association_name, *(args << block))
88 | end
89 |
90 | def fields_for_nested_model(name, object, options, block)
91 | classes = 'fields'
92 | classes << ' marked_for_destruction' if object.respond_to?(:marked_for_destruction?) && object.marked_for_destruction?
93 |
94 | perform_wrap = options.fetch(:nested_wrapper, true)
95 | perform_wrap &&= options[:wrapper] != false # wrap even if nil
96 |
97 | if perform_wrap
98 | @template.content_tag(:div, super, :class => classes)
99 | else
100 | super
101 | end
102 | end
103 |
104 | private
105 |
106 | def fields_blueprint_id_for(association)
107 | assocs = object_name.to_s.scan(/(\w+)_attributes/).map(&:first)
108 | assocs << association
109 | assocs.join('_') + '_fields_blueprint'
110 | end
111 | end
112 | end
113 |
--------------------------------------------------------------------------------
/lib/nested_form/builders.rb:
--------------------------------------------------------------------------------
1 | require 'nested_form/builder_mixin'
2 |
3 | module NestedForm
4 | class Builder < ::ActionView::Helpers::FormBuilder
5 | include ::NestedForm::BuilderMixin
6 | end
7 |
8 | begin
9 | require 'simple_form'
10 | class SimpleBuilder < ::SimpleForm::FormBuilder
11 | include ::NestedForm::BuilderMixin
12 | end
13 | rescue LoadError
14 | end
15 |
16 | begin
17 | require 'formtastic'
18 | class FormtasticBuilder < (defined?(::Formtastic::FormBuilder) ? Formtastic::FormBuilder : ::Formtastic::SemanticFormBuilder)
19 | include ::NestedForm::BuilderMixin
20 | end
21 | rescue LoadError
22 | end
23 |
24 | begin
25 | require 'formtastic-bootstrap'
26 | class FormtasticBootstrapBuilder < ::FormtasticBootstrap::FormBuilder
27 | include ::NestedForm::BuilderMixin
28 | end
29 | rescue LoadError
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/lib/nested_form/engine.rb:
--------------------------------------------------------------------------------
1 | require 'rails'
2 |
3 | module NestedForm
4 | class Engine < ::Rails::Engine
5 | initializer 'nested_form' do |app|
6 | ActiveSupport.on_load(:action_view) do
7 | require "nested_form/view_helper"
8 | class ActionView::Base
9 | include NestedForm::ViewHelper
10 | end
11 | end
12 | end
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/lib/nested_form/view_helper.rb:
--------------------------------------------------------------------------------
1 | require 'nested_form/builders'
2 |
3 | module NestedForm
4 | module ViewHelper
5 | def nested_form_for(*args, &block)
6 | options = args.extract_options!.reverse_merge(:builder => NestedForm::Builder)
7 | form_for(*(args << options)) do |f|
8 | capture(f, &block).to_s << after_nested_form_callbacks
9 | end
10 | end
11 |
12 | if defined?(NestedForm::SimpleBuilder)
13 | def simple_nested_form_for(*args, &block)
14 | options = args.extract_options!.reverse_merge(:builder => NestedForm::SimpleBuilder)
15 | simple_form_for(*(args << options)) do |f|
16 | capture(f, &block).to_s << after_nested_form_callbacks
17 | end
18 | end
19 | end
20 |
21 | if defined?(NestedForm::FormtasticBuilder)
22 | def semantic_nested_form_for(*args, &block)
23 | options = args.extract_options!.reverse_merge(:builder => NestedForm::FormtasticBuilder)
24 | semantic_form_for(*(args << options)) do |f|
25 | capture(f, &block).to_s << after_nested_form_callbacks
26 | end
27 | end
28 | end
29 |
30 | if defined?(NestedForm::FormtasticBootstrapBuilder)
31 | def semantic_bootstrap_nested_form_for(*args, &block)
32 | options = args.extract_options!.reverse_merge(:builder => NestedForm::FormtasticBootstrapBuilder)
33 | semantic_form_for(*(args << options)) do |f|
34 | capture(f, &block).to_s << after_nested_form_callbacks
35 | end
36 | end
37 | end
38 |
39 | def after_nested_form(association, &block)
40 | @associations ||= []
41 | @after_nested_form_callbacks ||= []
42 | unless @associations.include?(association)
43 | @associations << association
44 | @after_nested_form_callbacks << block
45 | end
46 | end
47 |
48 | private
49 | def after_nested_form_callbacks
50 | @after_nested_form_callbacks ||= []
51 | fields = []
52 | while callback = @after_nested_form_callbacks.shift
53 | fields << callback.call
54 | end
55 | fields.join(" ").html_safe
56 | end
57 | end
58 | end
59 |
--------------------------------------------------------------------------------
/nested_form.gemspec:
--------------------------------------------------------------------------------
1 | Gem::Specification.new do |s|
2 | s.name = "nested_form"
3 | s.version = "0.3.2"
4 | s.authors = ["Ryan Bates", "Andrea Singh"]
5 | s.email = "ryan@railscasts.com"
6 | s.homepage = "http://github.com/ryanb/nested_form"
7 | s.summary = "Gem to conveniently handle multiple models in a single form."
8 | s.description = "Gem to conveniently handle multiple models in a single form with Rails 3 and jQuery or Prototype."
9 |
10 | s.files = Dir["{lib,spec,vendor}/**/*", "[A-Z]*"] - ["Gemfile.lock"]
11 | s.require_path = "lib"
12 |
13 | s.add_development_dependency "rake"
14 | s.add_development_dependency "bundler"
15 | s.add_development_dependency "rspec-rails", "~> 2.6"
16 | s.add_development_dependency "mocha"
17 | s.add_development_dependency "capybara", "~> 1.1"
18 |
19 | s.rubyforge_project = s.name
20 | s.required_rubygems_version = ">= 1.3.4"
21 | end
22 |
--------------------------------------------------------------------------------
/spec/dummy/Rakefile:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env rake
2 | # Add your own tasks in files placed in lib/tasks ending in .rake,
3 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
4 |
5 | require File.expand_path('../config/application', __FILE__)
6 |
7 | Dummy::Application.load_tasks
8 |
--------------------------------------------------------------------------------
/spec/dummy/app/assets/javascripts/application.js:
--------------------------------------------------------------------------------
1 | // This is a manifest file that'll be compiled into including all the files listed below.
2 | // Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
3 | // be included in the compiled file accessible from http://example.com/assets/application.js
4 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
5 | // the compiled file.
6 |
--------------------------------------------------------------------------------
/spec/dummy/app/assets/javascripts/jquery_events_test.js:
--------------------------------------------------------------------------------
1 | $(function() {
2 | var log = function(text) {
3 | $('', {text: text}).appendTo('#console');
4 | };
5 |
6 | ['Added', 'Removed'].forEach(function(action) {
7 | $(document).on('nested:field' + action, function(e) {
8 | log(action + ' some field')
9 | });
10 |
11 | $(document).on('nested:field' + action + ':tasks', function(e) {
12 | log(action + ' task field')
13 | });
14 |
15 | $(document).on('nested:field' + action + ':milestones', function(e) {
16 | log(action + ' milestone field')
17 | });
18 | });
19 | });
--------------------------------------------------------------------------------
/spec/dummy/app/assets/javascripts/jquery_nested_form.js:
--------------------------------------------------------------------------------
1 | ../../../../../vendor/assets/javascripts/jquery_nested_form.js
--------------------------------------------------------------------------------
/spec/dummy/app/assets/javascripts/projects.js:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/spec/dummy/app/assets/javascripts/prototype_events_test.js:
--------------------------------------------------------------------------------
1 | document.observe('dom:loaded', function() {
2 | var log = function(text) {
3 | var p = new Element('p').update(text);
4 | $('console').insert(p);
5 | };
6 |
7 | ['Added', 'Removed'].forEach(function(action) {
8 | document.observe('nested:field' + action, function(e) {
9 | log(action + ' some field')
10 | });
11 |
12 | document.observe('nested:field' + action + ':tasks', function(e) {
13 | log(action + ' task field')
14 | });
15 |
16 | document.observe('nested:field' + action + ':milestones', function(e) {
17 | log(action + ' milestone field')
18 | });
19 | });
20 | });
--------------------------------------------------------------------------------
/spec/dummy/app/assets/javascripts/prototype_nested_form.js:
--------------------------------------------------------------------------------
1 | ../../../../../vendor/assets/javascripts/prototype_nested_form.js
--------------------------------------------------------------------------------
/spec/dummy/app/assets/stylesheets/application.css:
--------------------------------------------------------------------------------
1 | /*
2 | * This is a manifest file that'll automatically include all the stylesheets available in this directory
3 | * and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
4 | * the top of the compiled file, but it's generally better to create a new file per style scope.
5 | *= require_self
6 | *= require_tree .
7 | */
--------------------------------------------------------------------------------
/spec/dummy/app/assets/stylesheets/companies.css:
--------------------------------------------------------------------------------
1 | /*
2 | Place all the styles related to the matching controller here.
3 | They will automatically be included in application.css.
4 | */
5 |
--------------------------------------------------------------------------------
/spec/dummy/app/assets/stylesheets/projects.css:
--------------------------------------------------------------------------------
1 | /*
2 | Place all the styles related to the matching controller here.
3 | They will automatically be included in application.css.
4 | */
5 |
--------------------------------------------------------------------------------
/spec/dummy/app/controllers/application_controller.rb:
--------------------------------------------------------------------------------
1 | class ApplicationController < ActionController::Base
2 | protect_from_forgery
3 | end
4 |
--------------------------------------------------------------------------------
/spec/dummy/app/controllers/companies_controller.rb:
--------------------------------------------------------------------------------
1 | class CompaniesController < ApplicationController
2 | def new
3 | @company = Company.new
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/spec/dummy/app/controllers/projects_controller.rb:
--------------------------------------------------------------------------------
1 | class ProjectsController < ApplicationController
2 | def new
3 | @project = Project.new
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/spec/dummy/app/helpers/application_helper.rb:
--------------------------------------------------------------------------------
1 | module ApplicationHelper
2 | end
3 |
--------------------------------------------------------------------------------
/spec/dummy/app/helpers/projects_helper.rb:
--------------------------------------------------------------------------------
1 | module ProjectsHelper
2 | end
3 |
--------------------------------------------------------------------------------
/spec/dummy/app/mailers/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ryanb/nested_form/78ad0469e681f159072e04c9c57d8722c9826295/spec/dummy/app/mailers/.gitkeep
--------------------------------------------------------------------------------
/spec/dummy/app/models/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ryanb/nested_form/78ad0469e681f159072e04c9c57d8722c9826295/spec/dummy/app/models/.gitkeep
--------------------------------------------------------------------------------
/spec/dummy/app/models/company.rb:
--------------------------------------------------------------------------------
1 | class Company < ActiveRecord::Base
2 | has_one :project
3 | accepts_nested_attributes_for :project
4 |
5 | after_initialize 'self.build_project'
6 | end
7 |
--------------------------------------------------------------------------------
/spec/dummy/app/models/milestone.rb:
--------------------------------------------------------------------------------
1 | class Milestone < ActiveRecord::Base
2 | belongs_to :task
3 | end
4 |
--------------------------------------------------------------------------------
/spec/dummy/app/models/project.rb:
--------------------------------------------------------------------------------
1 | class Project < ActiveRecord::Base
2 | has_many :tasks
3 | has_many :assignments, :class_name => 'ProjectTask'
4 | accepts_nested_attributes_for :tasks
5 | accepts_nested_attributes_for :assignments
6 |
7 | has_many :not_nested_tasks, :class_name => 'Task'
8 | end
9 |
--------------------------------------------------------------------------------
/spec/dummy/app/models/project_task.rb:
--------------------------------------------------------------------------------
1 | class ProjectTask < ActiveRecord::Base
2 | belongs_to :project
3 | end
--------------------------------------------------------------------------------
/spec/dummy/app/models/task.rb:
--------------------------------------------------------------------------------
1 | class Task < ActiveRecord::Base
2 | belongs_to :project
3 | has_many :milestones
4 | accepts_nested_attributes_for :milestones
5 | end
6 |
--------------------------------------------------------------------------------
/spec/dummy/app/views/companies/new.html.erb:
--------------------------------------------------------------------------------
1 | <%= nested_form_for @company do |f| -%>
2 | <%= f.text_field :name %>
3 | <%= f.fields_for :project do |pf| -%>
4 | <%= pf.text_field :name %>
5 | <%= pf.fields_for :tasks do |tf| -%>
6 | <%= tf.text_field :name %>
7 | <%= tf.fields_for :milestones do |mf| %>
8 | <%= mf.text_field :name %>
9 | <%= mf.link_to_remove 'Remove milestone' %>
10 | <% end %>
11 | <%= tf.link_to_add 'Add new milestone', :milestones %>
12 | <%= tf.link_to_remove 'Remove' %>
13 | <% end -%>
14 | <%= pf.link_to_add 'Add new task', :tasks %>
15 | <% end -%>
16 | <% end -%>
17 |
--------------------------------------------------------------------------------
/spec/dummy/app/views/layouts/application.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Dummy
5 |
6 | <% if params[:type] == 'prototype' %>
7 | <%= javascript_include_tag 'prototype', 'prototype_nested_form', 'prototype_events_test' %>
8 | <% else %>
9 | <%= javascript_include_tag 'jquery', 'jquery_nested_form', 'jquery_events_test' %>
10 | <% end %>
11 |
12 |
13 |
14 | <%= yield %>
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/spec/dummy/app/views/projects/new.html.erb:
--------------------------------------------------------------------------------
1 | <%= nested_form_for @project do |f| -%>
2 | <%= f.text_field :name %>
3 | <%= f.fields_for :tasks do |tf| -%>
4 | <%= tf.text_field :name %>
5 | <%= tf.fields_for :milestones do |mf| %>
6 | <%= mf.text_field :name %>
7 | <%= mf.link_to_remove 'Remove milestone' %>
8 | <% end %>
9 | <%= tf.link_to_add 'Add new milestone', :milestones %>
10 | <%= tf.link_to_remove 'Remove' %>
11 | <% end -%>
12 | <%= f.link_to_add 'Add new task', :tasks %>
13 | <% end -%>
14 |
--------------------------------------------------------------------------------
/spec/dummy/app/views/projects/without_intermediate_inputs.html.erb:
--------------------------------------------------------------------------------
1 | <%= nested_form_for Project.new do |f| -%>
2 | <%= f.fields_for :tasks do |tf| -%>
3 | <%= tf.fields_for :milestones do |mf| %>
4 | <%= mf.text_field :name %>
5 | <%= mf.link_to_remove 'Remove milestone' %>
6 | <% end %>
7 | <%= tf.link_to_add 'Add new milestone', :milestones %>
8 | <%= tf.link_to_remove 'Remove' %>
9 | <% end -%>
10 | <%= f.link_to_add 'Add new task', :tasks %>
11 | <% end -%>
12 |
--------------------------------------------------------------------------------
/spec/dummy/config.ru:
--------------------------------------------------------------------------------
1 | # This file is used by Rack-based servers to start the application.
2 |
3 | require ::File.expand_path('../config/environment', __FILE__)
4 | run Dummy::Application
5 |
--------------------------------------------------------------------------------
/spec/dummy/config/application.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../boot', __FILE__)
2 |
3 | require 'rails/all'
4 |
5 | Bundler.require
6 | require "nested_form"
7 |
8 | module Dummy
9 | class Application < Rails::Application
10 | # Settings in config/environments/* take precedence over those specified here.
11 | # Application configuration should go into files in config/initializers
12 | # -- all .rb files in that directory are automatically loaded.
13 |
14 | # Custom directories with classes and modules you want to be autoloadable.
15 | # config.autoload_paths += %W(#{config.root}/extras)
16 |
17 | # Only load the plugins named here, in the order given (default is alphabetical).
18 | # :all can be used as a placeholder for all plugins not explicitly named.
19 | # config.plugins = [ :exception_notification, :ssl_requirement, :all ]
20 |
21 | # Activate observers that should always be running.
22 | # config.active_record.observers = :cacher, :garbage_collector, :forum_observer
23 |
24 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
25 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
26 | # config.time_zone = 'Central Time (US & Canada)'
27 |
28 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
29 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
30 | # config.i18n.default_locale = :de
31 |
32 | # Configure the default encoding used in templates for Ruby 1.9.
33 | config.encoding = "utf-8"
34 |
35 | # Configure sensitive parameters which will be filtered from the log file.
36 | config.filter_parameters += [:password]
37 |
38 | # Enable the asset pipeline
39 | config.assets.enabled = true if config.respond_to?(:assets)
40 | end
41 | end
42 |
43 |
--------------------------------------------------------------------------------
/spec/dummy/config/boot.rb:
--------------------------------------------------------------------------------
1 | require 'rubygems'
2 |
3 | gemfile = ENV['BUNDLE_GEMFILE'] || File.expand_path('../../../../Gemfile', __FILE__)
4 | if File.exist?(gemfile)
5 | ENV['BUNDLE_GEMFILE'] = gemfile
6 | require 'bundler'
7 | Bundler.setup
8 | end
9 |
10 | $:.unshift File.expand_path('../../../../lib', __FILE__)
11 |
--------------------------------------------------------------------------------
/spec/dummy/config/database.yml:
--------------------------------------------------------------------------------
1 | # SQLite version 3.x
2 | # gem install sqlite3
3 | #
4 | # Ensure the SQLite 3 gem is defined in your Gemfile
5 | # gem 'sqlite3'
6 | development:
7 | adapter: sqlite3
8 | database: db/development.sqlite3
9 | pool: 5
10 | timeout: 5000
11 |
12 | # Warning: The database defined as "test" will be erased and
13 | # re-generated from your development database when you run "rake".
14 | # Do not set this db to the same as development or production.
15 | test:
16 | adapter: sqlite3
17 | database: db/test.sqlite3
18 | pool: 5
19 | timeout: 5000
20 |
21 | production:
22 | adapter: sqlite3
23 | database: db/production.sqlite3
24 | pool: 5
25 | timeout: 5000
26 |
--------------------------------------------------------------------------------
/spec/dummy/config/environment.rb:
--------------------------------------------------------------------------------
1 | # Load the rails application
2 | require File.expand_path('../application', __FILE__)
3 |
4 | # Initialize the rails application
5 | Dummy::Application.initialize!
6 |
--------------------------------------------------------------------------------
/spec/dummy/config/environments/development.rb:
--------------------------------------------------------------------------------
1 | Dummy::Application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb
3 |
4 | # In the development environment your application's code is reloaded on
5 | # every request. This slows down response time but is perfect for development
6 | # since you don't have to restart the web server when you make code changes.
7 | config.cache_classes = false
8 |
9 | # Log error messages when you accidentally call methods on nil.
10 | config.whiny_nils = true
11 |
12 | # Show full error reports and disable caching
13 | config.consider_all_requests_local = true
14 | config.action_controller.perform_caching = false
15 |
16 | # Don't care if the mailer can't send
17 | config.action_mailer.raise_delivery_errors = false
18 |
19 | # Print deprecation notices to the Rails logger
20 | config.active_support.deprecation = :log
21 |
22 | # Only use best-standards-support built into browsers
23 | config.action_dispatch.best_standards_support = :builtin
24 |
25 | # Do not compress assets
26 | config.assets.compress = false if config.respond_to?(:assets)
27 | end
28 |
--------------------------------------------------------------------------------
/spec/dummy/config/environments/production.rb:
--------------------------------------------------------------------------------
1 | Dummy::Application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb
3 |
4 | # Code is not reloaded between requests
5 | config.cache_classes = true
6 |
7 | # Full error reports are disabled and caching is turned on
8 | config.consider_all_requests_local = false
9 | config.action_controller.perform_caching = true
10 |
11 | # Disable Rails's static asset server (Apache or nginx will already do this)
12 | config.serve_static_assets = false
13 |
14 | # Compress JavaScripts and CSS
15 | config.assets.compress = true
16 |
17 | # Specify the default JavaScript compressor
18 | config.assets.js_compressor = :uglifier
19 |
20 | # Specifies the header that your server uses for sending files
21 | # (comment out if your front-end server doesn't support this)
22 | config.action_dispatch.x_sendfile_header = "X-Sendfile" # Use 'X-Accel-Redirect' for nginx
23 |
24 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
25 | # config.force_ssl = true
26 |
27 | # See everything in the log (default is :info)
28 | # config.log_level = :debug
29 |
30 | # Use a different logger for distributed setups
31 | # config.logger = SyslogLogger.new
32 |
33 | # Use a different cache store in production
34 | # config.cache_store = :mem_cache_store
35 |
36 | # Enable serving of images, stylesheets, and JavaScripts from an asset server
37 | # config.action_controller.asset_host = "http://assets.example.com"
38 |
39 | # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added)
40 | # config.assets.precompile += %w( search.js )
41 |
42 | # Disable delivery errors, bad email addresses will be ignored
43 | # config.action_mailer.raise_delivery_errors = false
44 |
45 | # Enable threaded mode
46 | # config.threadsafe!
47 |
48 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
49 | # the I18n.default_locale when a translation can not be found)
50 | config.i18n.fallbacks = true
51 |
52 | # Send deprecation notices to registered listeners
53 | config.active_support.deprecation = :notify
54 | end
55 |
--------------------------------------------------------------------------------
/spec/dummy/config/environments/test.rb:
--------------------------------------------------------------------------------
1 | Dummy::Application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb
3 |
4 | # The test environment is used exclusively to run your application's
5 | # test suite. You never need to work with it otherwise. Remember that
6 | # your test database is "scratch space" for the test suite and is wiped
7 | # and recreated between test runs. Don't rely on the data there!
8 | config.cache_classes = true
9 |
10 | # Configure static asset server for tests with Cache-Control for performance
11 | config.serve_static_assets = true
12 | config.static_cache_control = "public, max-age=3600"
13 |
14 | # Log error messages when you accidentally call methods on nil
15 | config.whiny_nils = true
16 |
17 | # Show full error reports and disable caching
18 | config.consider_all_requests_local = true
19 | config.action_controller.perform_caching = false
20 |
21 | # Raise exceptions instead of rendering exception templates
22 | config.action_dispatch.show_exceptions = false
23 |
24 | # Disable request forgery protection in test environment
25 | config.action_controller.allow_forgery_protection = false
26 |
27 | # Tell Action Mailer not to deliver emails to the real world.
28 | # The :test delivery method accumulates sent emails in the
29 | # ActionMailer::Base.deliveries array.
30 | config.action_mailer.delivery_method = :test
31 |
32 | # Use SQL instead of Active Record's schema dumper when creating the test database.
33 | # This is necessary if your schema can't be completely dumped by the schema dumper,
34 | # like if you have constraints or database-specific column types
35 | # config.active_record.schema_format = :sql
36 |
37 | # Print deprecation notices to the stderr
38 | config.active_support.deprecation = :stderr
39 | end
40 |
--------------------------------------------------------------------------------
/spec/dummy/config/initializers/backtrace_silencers.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
5 |
6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
7 | # Rails.backtrace_cleaner.remove_silencers!
8 |
--------------------------------------------------------------------------------
/spec/dummy/config/initializers/inflections.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Add new inflection rules using the following format
4 | # (all these examples are active by default):
5 | # ActiveSupport::Inflector.inflections do |inflect|
6 | # inflect.plural /^(ox)$/i, '\1en'
7 | # inflect.singular /^(ox)en/i, '\1'
8 | # inflect.irregular 'person', 'people'
9 | # inflect.uncountable %w( fish sheep )
10 | # end
11 |
--------------------------------------------------------------------------------
/spec/dummy/config/initializers/mime_types.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Add new mime types for use in respond_to blocks:
4 | # Mime::Type.register "text/richtext", :rtf
5 | # Mime::Type.register_alias "text/html", :iphone
6 |
--------------------------------------------------------------------------------
/spec/dummy/config/initializers/secret_token.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Your secret key for verifying the integrity of signed cookies.
4 | # If you change this key, all old signed cookies will become invalid!
5 | # Make sure the secret is at least 30 characters and all random,
6 | # no regular words or you'll be exposed to dictionary attacks.
7 | Dummy::Application.config.secret_token = '34d776d7b34c759d74790e5cc10edfaf610a403281e7cda53f0c25e750dc4b774d1a1a59d0ca3698e11ea260c57fcaa6c98b9aee9e62a95ffd9f7f91f21db18d'
8 |
--------------------------------------------------------------------------------
/spec/dummy/config/initializers/session_store.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | Dummy::Application.config.session_store :cookie_store, :key => '_dummy_session'
4 |
5 | # Use the database for sessions instead of the cookie-based default,
6 | # which shouldn't be used to store highly confidential information
7 | # (create the session table with "rails generate session_migration")
8 | # Dummy::Application.config.session_store :active_record_store
9 |
--------------------------------------------------------------------------------
/spec/dummy/config/initializers/wrap_parameters.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 | #
3 | # This file contains settings for ActionController::ParamsWrapper which
4 | # is enabled by default.
5 |
6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
7 | ActionController::Base.wrap_parameters :format => [:json] if ActionController::Base.respond_to?(:wrap_parameters)
8 |
9 | # Disable root element in JSON by default.
10 | if defined?(ActiveRecord)
11 | ActiveRecord::Base.include_root_in_json = false
12 | end
13 |
--------------------------------------------------------------------------------
/spec/dummy/config/locales/en.yml:
--------------------------------------------------------------------------------
1 | # Sample localization file for English. Add more files in this directory for other locales.
2 | # See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points.
3 |
4 | en:
5 | hello: "Hello world"
6 |
--------------------------------------------------------------------------------
/spec/dummy/config/routes.rb:
--------------------------------------------------------------------------------
1 | Dummy::Application.routes.draw do
2 | resources :companies, :only => %w(new create)
3 | resources :projects, :only => %w(new create)
4 | get '/:controller/:action'
5 |
6 | # The priority is based upon order of creation:
7 | # first created -> highest priority.
8 |
9 | # Sample of regular route:
10 | # match 'products/:id' => 'catalog#view'
11 | # Keep in mind you can assign values other than :controller and :action
12 |
13 | # Sample of named route:
14 | # match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase
15 | # This route can be invoked with purchase_url(:id => product.id)
16 |
17 | # Sample resource route (maps HTTP verbs to controller actions automatically):
18 | # resources :products
19 |
20 | # Sample resource route with options:
21 | # resources :products do
22 | # member do
23 | # get 'short'
24 | # post 'toggle'
25 | # end
26 | #
27 | # collection do
28 | # get 'sold'
29 | # end
30 | # end
31 |
32 | # Sample resource route with sub-resources:
33 | # resources :products do
34 | # resources :comments, :sales
35 | # resource :seller
36 | # end
37 |
38 | # Sample resource route with more complex sub-resources
39 | # resources :products do
40 | # resources :comments
41 | # resources :sales do
42 | # get 'recent', :on => :collection
43 | # end
44 | # end
45 |
46 | # Sample resource route within a namespace:
47 | # namespace :admin do
48 | # # Directs /admin/products/* to Admin::ProductsController
49 | # # (app/controllers/admin/products_controller.rb)
50 | # resources :products
51 | # end
52 |
53 | # You can have the root of your site routed with "root"
54 | # just remember to delete public/index.html.
55 | # root :to => 'welcome#index'
56 |
57 | # See how all your routes lay out with "rake routes"
58 |
59 | # This is a legacy wild controller route that's not recommended for RESTful applications.
60 | # Note: This route will make all actions in every controller accessible via GET requests.
61 | # match ':controller(/:action(/:id(.:format)))'
62 | end
63 |
--------------------------------------------------------------------------------
/spec/dummy/db/migrate/20110710143903_initial_tables.rb:
--------------------------------------------------------------------------------
1 | class InitialTables < ActiveRecord::Migration
2 | def self.up
3 | create_table :projects do |t|
4 | t.string :name
5 | end
6 |
7 | create_table :tasks do |t|
8 | t.integer :project_id
9 | t.string :name
10 | end
11 |
12 | create_table :milestones do |t|
13 | t.integer :task_id
14 | t.string :name
15 | end
16 | end
17 |
18 | def self.down
19 | drop_table :projects
20 | drop_table :tasks
21 | drop_table :milestones
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/spec/dummy/db/migrate/20120819164528_add_association_with_class_name.rb:
--------------------------------------------------------------------------------
1 | class AddAssociationWithClassName < ActiveRecord::Migration
2 | def self.up
3 | create_table :project_tasks do |t|
4 | t.integer :project_id
5 | t.string :name
6 | end
7 | end
8 |
9 | def self.down
10 | drop_table :project_tasks
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/spec/dummy/db/migrate/20130203095901_create_company.rb:
--------------------------------------------------------------------------------
1 | class CreateCompany < ActiveRecord::Migration
2 | def self.up
3 | create_table :companies do |t|
4 | t.string :name
5 | end
6 |
7 | add_column :projects, :company_id, :integer
8 | end
9 |
10 | def self.down
11 | remove_column :projects, :company_id
12 | drop_table :companies
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/spec/dummy/db/schema.rb:
--------------------------------------------------------------------------------
1 | # encoding: UTF-8
2 | # This file is auto-generated from the current state of the database. Instead
3 | # of editing this file, please use the migrations feature of Active Record to
4 | # incrementally modify your database, and then regenerate this schema definition.
5 | #
6 | # Note that this schema.rb definition is the authoritative source for your
7 | # database schema. If you need to create the application database on another
8 | # system, you should be using db:schema:load, not running all the migrations
9 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations
10 | # you'll amass, the slower it'll run and the greater likelihood for issues).
11 | #
12 | # It's strongly recommended to check this file into your version control system.
13 |
14 | ActiveRecord::Schema.define(:version => 20130203095901) do
15 |
16 | create_table "companies", :force => true do |t|
17 | t.string "name"
18 | end
19 |
20 | create_table "milestones", :force => true do |t|
21 | t.integer "task_id"
22 | t.string "name"
23 | end
24 |
25 | create_table "project_tasks", :force => true do |t|
26 | t.integer "project_id"
27 | t.string "name"
28 | end
29 |
30 | create_table "projects", :force => true do |t|
31 | t.string "name"
32 | t.integer "company_id"
33 | end
34 |
35 | create_table "tasks", :force => true do |t|
36 | t.integer "project_id"
37 | t.string "name"
38 | end
39 |
40 | end
41 |
--------------------------------------------------------------------------------
/spec/dummy/public/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The page you were looking for doesn't exist (404)
5 |
17 |
18 |
19 |
20 |
21 |
22 |
The page you were looking for doesn't exist.
23 |
You may have mistyped the address or the page may have moved.