giraffesoft-attribute_fu 0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README +115 -0
  3. data/Rakefile +22 -0
  4. data/init.rb +2 -0
  5. data/lib/attribute_fu.rb +2 -0
  6. data/lib/attribute_fu/associated_form_helper.rb +139 -0
  7. data/lib/attribute_fu/associations.rb +124 -0
  8. data/tasks/attribute_fu_tasks.rake +4 -0
  9. data/test/Rakefile +10 -0
  10. data/test/app/controllers/application.rb +10 -0
  11. data/test/app/helpers/application_helper.rb +3 -0
  12. data/test/app/models/comment.rb +8 -0
  13. data/test/app/models/photo.rb +3 -0
  14. data/test/config/boot.rb +97 -0
  15. data/test/config/database.yml +15 -0
  16. data/test/config/environment.rb +15 -0
  17. data/test/config/environments/development.rb +18 -0
  18. data/test/config/environments/test.rb +22 -0
  19. data/test/config/routes.rb +35 -0
  20. data/test/db/migrate/001_create_photos.rb +14 -0
  21. data/test/db/migrate/002_create_comments.rb +15 -0
  22. data/test/db/schema.rb +29 -0
  23. data/test/script/console +3 -0
  24. data/test/script/destroy +3 -0
  25. data/test/script/generate +3 -0
  26. data/test/script/server +3 -0
  27. data/test/test/test_helper.rb +6 -0
  28. data/test/test/unit/associated_form_helper_test.rb +376 -0
  29. data/test/test/unit/comment_test.rb +6 -0
  30. data/test/test/unit/photo_test.rb +149 -0
  31. data/test/vendor/plugins/shoulda/init.rb +3 -0
  32. data/test/vendor/plugins/shoulda/lib/shoulda.rb +20 -0
  33. data/test/vendor/plugins/shoulda/lib/shoulda/active_record_helpers.rb +338 -0
  34. data/test/vendor/plugins/shoulda/lib/shoulda/context.rb +143 -0
  35. data/test/vendor/plugins/shoulda/lib/shoulda/general.rb +119 -0
  36. data/test/vendor/plugins/shoulda/lib/shoulda/private_helpers.rb +17 -0
  37. data/uninstall.rb +1 -0
  38. metadata +110 -0
@@ -0,0 +1,10 @@
1
+ # Filters added to this controller apply to all controllers in the application.
2
+ # Likewise, all the methods added will be available for all controllers.
3
+
4
+ class ApplicationController < ActionController::Base
5
+ helper :all # include all helpers, all the time
6
+
7
+ # See ActionController::RequestForgeryProtection for details
8
+ # Uncomment the :secret if you're not using the cookie session store
9
+ protect_from_forgery # :secret => '012cbaf0c3d36504f3b1bc397b838d24'
10
+ end
@@ -0,0 +1,3 @@
1
+ # Methods added to this helper will be available to all templates in the application.
2
+ module ApplicationHelper
3
+ end
@@ -0,0 +1,8 @@
1
+ class Comment < ActiveRecord::Base
2
+ belongs_to :photo
3
+ validates_presence_of :author, :body
4
+
5
+ def blank?
6
+ author.blank? && body.blank?
7
+ end
8
+ end
@@ -0,0 +1,3 @@
1
+ class Photo < ActiveRecord::Base
2
+ has_many :comments, :attributes => true
3
+ end
@@ -0,0 +1,97 @@
1
+ # Don't change this file!
2
+ # Configure your app in config/environment.rb and config/environments/*.rb
3
+
4
+ RAILS_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(RAILS_ROOT)
5
+
6
+ module Rails
7
+ class << self
8
+ def boot!
9
+ pick_boot.run unless booted?
10
+ end
11
+
12
+ def booted?
13
+ defined? Rails::Initializer
14
+ end
15
+
16
+ def pick_boot
17
+ (vendor_rails? ? VendorBoot : GemBoot).new
18
+ end
19
+
20
+ def vendor_rails?
21
+ File.exist?("#{RAILS_ROOT}/vendor/rails")
22
+ end
23
+ end
24
+
25
+ class Boot
26
+ def run
27
+ load_initializer
28
+ Rails::Initializer.run(:set_load_path)
29
+ end
30
+ end
31
+
32
+ class VendorBoot < Boot
33
+ def load_initializer
34
+ require "#{RAILS_ROOT}/vendor/rails/railties/lib/initializer"
35
+ end
36
+ end
37
+
38
+ class GemBoot < Boot
39
+ def load_initializer
40
+ self.class.load_rubygems
41
+ load_rails_gem
42
+ require 'initializer'
43
+ end
44
+
45
+ def load_rails_gem
46
+ if version = self.class.gem_version
47
+ gem 'rails', "=#{version}"
48
+ else
49
+ gem 'rails'
50
+ end
51
+ rescue Gem::LoadError => load_error
52
+ $stderr.puts %(Missing the Rails #{version} gem. Please `gem install -v=#{version} rails`, update your RAILS_GEM_VERSION setting in config/environment.rb for the Rails version you do have installed, or comment out RAILS_GEM_VERSION to use the latest version installed.)
53
+ exit 1
54
+ end
55
+
56
+ class << self
57
+ def rubygems_version
58
+ Gem::RubyGemsVersion if defined? Gem::RubyGemsVersion
59
+ end
60
+
61
+ def gem_version
62
+ if defined? RAILS_GEM_VERSION
63
+ RAILS_GEM_VERSION
64
+ elsif ENV.include?('RAILS_GEM_VERSION')
65
+ ENV['RAILS_GEM_VERSION']
66
+ else
67
+ parse_gem_version(read_environment_rb)
68
+ end
69
+ end
70
+
71
+ def load_rubygems
72
+ require 'rubygems'
73
+
74
+ unless rubygems_version >= '0.9.4'
75
+ $stderr.puts %(Rails requires RubyGems >= 0.9.4 (you have #{rubygems_version}). Please `gem update --system` and try again.)
76
+ exit 1
77
+ end
78
+
79
+ rescue LoadError
80
+ $stderr.puts %(Rails requires RubyGems >= 0.9.4. Please install RubyGems and try again: http://rubygems.rubyforge.org)
81
+ exit 1
82
+ end
83
+
84
+ def parse_gem_version(text)
85
+ $1 if text =~ /^[^#]*RAILS_GEM_VERSION\s*=\s*'([\d.]+)'/
86
+ end
87
+
88
+ private
89
+ def read_environment_rb
90
+ File.read("#{RAILS_ROOT}/config/environment.rb")
91
+ end
92
+ end
93
+ end
94
+ end
95
+
96
+ # All that for this:
97
+ Rails.boot!
@@ -0,0 +1,15 @@
1
+ development:
2
+ adapter: mysql
3
+ encoding: utf8
4
+ database: attribute_fu_test
5
+ username: root
6
+ password:
7
+ socket: /tmp/mysql.sock
8
+
9
+ test:
10
+ adapter: mysql
11
+ encoding: utf8
12
+ database: attribute_fu_test
13
+ username: root
14
+ password:
15
+ socket: /tmp/mysql.sock
@@ -0,0 +1,15 @@
1
+ $:.reject! { |e| e.include? 'TextMate' }
2
+ RAILS_GEM_VERSION = '2.0.2' unless defined? RAILS_GEM_VERSION
3
+
4
+ require File.join(File.dirname(__FILE__), 'boot')
5
+
6
+ Rails::Initializer.run do |config|
7
+ config.action_controller.session = {
8
+ :session_key => '_test_session',
9
+ :secret => '012cbaf0c3d36504f3b1bc397b838d24'
10
+ }
11
+
12
+ config.load_paths += %W( #{RAILS_ROOT}/../lib )
13
+ end
14
+
15
+ require "#{RAILS_ROOT}/../init"
@@ -0,0 +1,18 @@
1
+ # Settings specified here will take precedence over those in config/environment.rb
2
+
3
+ # In the development environment your application's code is reloaded on
4
+ # every request. This slows down response time but is perfect for development
5
+ # since you don't have to restart the webserver when you make code changes.
6
+ config.cache_classes = false
7
+
8
+ # Log error messages when you accidentally call methods on nil.
9
+ config.whiny_nils = true
10
+
11
+ # Show full error reports and disable caching
12
+ config.action_controller.consider_all_requests_local = true
13
+ config.action_controller.perform_caching = false
14
+ config.action_view.cache_template_extensions = false
15
+ config.action_view.debug_rjs = true
16
+
17
+ # Don't care if the mailer can't send
18
+ config.action_mailer.raise_delivery_errors = false
@@ -0,0 +1,22 @@
1
+ # Settings specified here will take precedence over those in config/environment.rb
2
+
3
+ # The test environment is used exclusively to run your application's
4
+ # test suite. You never need to work with it otherwise. Remember that
5
+ # your test database is "scratch space" for the test suite and is wiped
6
+ # and recreated between test runs. Don't rely on the data there!
7
+ config.cache_classes = true
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.action_controller.consider_all_requests_local = true
14
+ config.action_controller.perform_caching = false
15
+
16
+ # Disable request forgery protection in test environment
17
+ config.action_controller.allow_forgery_protection = false
18
+
19
+ # Tell ActionMailer not to deliver emails to the real world.
20
+ # The :test delivery method accumulates sent emails in the
21
+ # ActionMailer::Base.deliveries array.
22
+ config.action_mailer.delivery_method = :test
@@ -0,0 +1,35 @@
1
+ ActionController::Routing::Routes.draw do |map|
2
+ # The priority is based upon order of creation: first created -> highest priority.
3
+
4
+ # Sample of regular route:
5
+ # map.connect 'products/:id', :controller => 'catalog', :action => 'view'
6
+ # Keep in mind you can assign values other than :controller and :action
7
+
8
+ # Sample of named route:
9
+ # map.purchase 'products/:id/purchase', :controller => 'catalog', :action => 'purchase'
10
+ # This route can be invoked with purchase_url(:id => product.id)
11
+
12
+ # Sample resource route (maps HTTP verbs to controller actions automatically):
13
+ # map.resources :products
14
+
15
+ # Sample resource route with options:
16
+ # map.resources :products, :member => { :short => :get, :toggle => :post }, :collection => { :sold => :get }
17
+
18
+ # Sample resource route with sub-resources:
19
+ # map.resources :products, :has_many => [ :comments, :sales ], :has_one => :seller
20
+
21
+ # Sample resource route within a namespace:
22
+ # map.namespace :admin do |admin|
23
+ # # Directs /admin/products/* to Admin::ProductsController (app/controllers/admin/products_controller.rb)
24
+ # admin.resources :products
25
+ # end
26
+
27
+ # You can have the root of your site routed with map.root -- just remember to delete public/index.html.
28
+ # map.root :controller => "welcome"
29
+
30
+ # See how all your routes lay out with "rake routes"
31
+
32
+ # Install the default routes as the lowest priority.
33
+ map.connect ':controller/:action/:id'
34
+ map.connect ':controller/:action/:id.:format'
35
+ end
@@ -0,0 +1,14 @@
1
+ class CreatePhotos < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :photos do |t|
4
+ t.string :title
5
+ t.text :description
6
+
7
+ t.timestamps
8
+ end
9
+ end
10
+
11
+ def self.down
12
+ drop_table :photos
13
+ end
14
+ end
@@ -0,0 +1,15 @@
1
+ class CreateComments < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :comments do |t|
4
+ t.integer :photo_id
5
+ t.string :author
6
+ t.text :body
7
+
8
+ t.timestamps
9
+ end
10
+ end
11
+
12
+ def self.down
13
+ drop_table :comments
14
+ end
15
+ end
data/test/db/schema.rb ADDED
@@ -0,0 +1,29 @@
1
+ # This file is auto-generated from the current state of the database. Instead of editing this file,
2
+ # please use the migrations feature of ActiveRecord to incrementally modify your database, and
3
+ # then regenerate this schema definition.
4
+ #
5
+ # Note that this schema.rb definition is the authoritative source for your database schema. If you need
6
+ # to create the application database on another system, you should be using db:schema:load, not running
7
+ # all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations
8
+ # you'll amass, the slower it'll run and the greater likelihood for issues).
9
+ #
10
+ # It's strongly recommended to check this file into your version control system.
11
+
12
+ ActiveRecord::Schema.define(:version => 2) do
13
+
14
+ create_table "comments", :force => true do |t|
15
+ t.integer "photo_id"
16
+ t.string "author"
17
+ t.text "body"
18
+ t.datetime "created_at"
19
+ t.datetime "updated_at"
20
+ end
21
+
22
+ create_table "photos", :force => true do |t|
23
+ t.string "title"
24
+ t.text "description"
25
+ t.datetime "created_at"
26
+ t.datetime "updated_at"
27
+ end
28
+
29
+ end
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../config/boot'
3
+ require 'commands/console'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../config/boot'
3
+ require 'commands/destroy'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../config/boot'
3
+ require 'commands/generate'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../config/boot'
3
+ require 'commands/server'
@@ -0,0 +1,6 @@
1
+ ENV["RAILS_ENV"] = "test"
2
+ require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
3
+ require 'test_help'
4
+ require 'mocha'
5
+
6
+ class Test::Unit::TestCase; end
@@ -0,0 +1,376 @@
1
+ require File.dirname(__FILE__)+'/../test_helper'
2
+
3
+ class AssociatedFormHelperTest < Test::Unit::TestCase
4
+ include ActionView::Helpers::FormHelper
5
+ include ActionView::Helpers::FormTagHelper
6
+ include ActionView::Helpers::UrlHelper
7
+ include ActionView::Helpers::TagHelper
8
+ include ActionView::Helpers::TextHelper
9
+ include AttributeFu::AssociatedFormHelper
10
+
11
+ def setup
12
+ @photo = Photo.create
13
+ @controller = mock()
14
+ @controller.stubs(:url_for).returns 'asdf'
15
+ @controller.stubs(:protect_against_forgery?).returns false
16
+ stubs(:protect_against_forgery?).returns false
17
+ end
18
+
19
+ context "fields for associated" do
20
+ context "with existing object" do
21
+ setup do
22
+ @photo.comments.create :author => "Barry", :body => "Oooh I did good today..."
23
+
24
+ @erbout = assoc_output @photo.comments.first
25
+ end
26
+
27
+ should "name field with attribute_fu naming conventions" do
28
+ assert_match "photo[comment_attributes][#{@photo.comments.first.id}]", @erbout
29
+ end
30
+ end
31
+
32
+ context "with non-existent object" do
33
+ setup do
34
+ @erbout = assoc_output(@photo.comments.build) do |f|
35
+ f.fields_for_associated(@photo.comments.build) do |comment|
36
+ comment.text_field(:author)
37
+ end
38
+ end
39
+ end
40
+
41
+ should "name field with attribute_fu naming conventions" do
42
+ assert_match "photo[comment_attributes][new][0]", @erbout
43
+ end
44
+
45
+ should "maintain the numbering of the new object if called again" do
46
+ assert_match "photo[comment_attributes][new][1]", @erbout
47
+ end
48
+ end
49
+
50
+ context "with overridden name" do
51
+ setup do
52
+ _erbout = ''
53
+ fields_for(:photo) do |f|
54
+ f.fields_for_associated(@photo.comments.build, :name => :something_else) do |comment|
55
+ _erbout.concat comment.text_field(:author)
56
+ end
57
+ end
58
+
59
+ @erbout = _erbout
60
+ end
61
+
62
+ should "use override name" do
63
+ assert_dom_equal "<input name='photo[something_else_attributes][new][0][author]' size='30' type='text' id='photo_something_else_attributes__new__0_author' />", @erbout
64
+ end
65
+ end
66
+ end
67
+
68
+ context "remove link" do
69
+ context "with just a name" do
70
+ setup do
71
+ remove_link "remove"
72
+ end
73
+
74
+ should "create a link" do
75
+ assert_match ">remove</a>", @erbout
76
+ end
77
+
78
+ should "infer the name of the current @object in fields_for" do
79
+ assert_match "$(this).up('.comment').remove()", @erbout
80
+ end
81
+ end
82
+
83
+ context "with an alternate CSS selector" do
84
+ setup do
85
+ remove_link "remove", :selector => '.blah'
86
+ end
87
+
88
+ should "use the alternate selector" do
89
+ assert_match "$(this).up('.blah').remove()", @erbout
90
+ end
91
+ end
92
+
93
+ context "with an extra function" do
94
+ setup do
95
+ @other_function = "$('asdf').blah();"
96
+ remove_link "remove", :function => @other_function
97
+ end
98
+
99
+ should "still infer the name of the current @object in fields_for, and create the function as usual" do
100
+ assert_match "$(this).up('.comment').remove()", @erbout
101
+ end
102
+
103
+ should "append the secondary function" do
104
+ assert_match @other_function, @erbout
105
+ end
106
+ end
107
+ end
108
+
109
+ context "with javascript flag" do
110
+ setup do
111
+ _erbout = ''
112
+ fields_for(:photo) do |f|
113
+ _erbout.concat(f.fields_for_associated(@photo.comments.build, :javascript => true) do |comment|
114
+ comment.text_field(:author)
115
+ end)
116
+ end
117
+
118
+ @erbout = _erbout
119
+ end
120
+
121
+ should "use placeholders instead of numbers" do
122
+ assert_match 'photo[comment_attributes][new][#{number}]', @erbout
123
+ end
124
+ end
125
+
126
+ context "add_associated_link " do
127
+ setup do
128
+ comment = @photo.comments.build
129
+
130
+ _erbout = ''
131
+ fields_for(:photo) do |f|
132
+ f.stubs(:render_associated_form).with(comment, :fields_for => {:javascript => true}, :partial => 'comment')
133
+ _erbout.concat f.add_associated_link("Add Comment", comment, :class => 'something')
134
+ end
135
+
136
+ @erbout = _erbout
137
+ end
138
+
139
+ should "create link" do
140
+ assert_match ">Add Comment</a>", @erbout
141
+ end
142
+
143
+ should "insert into the bottom of the parent container by default" do
144
+ assert_match "Insertion.Bottom('comments'", @erbout
145
+ end
146
+
147
+ should "wrap the partial in a prototype template" do
148
+ assert_match "new Template", @erbout
149
+ assert_match "evaluate", @erbout
150
+ end
151
+
152
+ should "name the variable correctly" do
153
+ assert_match "attribute_fu_comment_count", @erbout
154
+ end
155
+
156
+ should "pass along the additional options to the link_to_function call" do
157
+ assert_match 'class="something"', @erbout
158
+ end
159
+
160
+ should "produce the following link" do
161
+ # this is a way of testing the whole link
162
+ assert_equal %{
163
+ <a class=\"something\" href=\"#\" onclick=\"if (typeof attribute_fu_comment_count == 'undefined') attribute_fu_comment_count = 0;\nnew Insertion.Bottom('comments', new Template(null).evaluate({'number': --attribute_fu_comment_count})); return false;\">Add Comment</a>
164
+ }.strip, @erbout
165
+ end
166
+ end
167
+
168
+ context "add_associated_link with parameters" do
169
+ setup do
170
+ comment = @photo.comments.build
171
+
172
+ _erbout = ''
173
+ fields_for(:photo) do |f|
174
+ f.stubs(:render_associated_form).with(comment, :fields_for => {:javascript => true}, :partial => 'some_other_partial')
175
+ _erbout.concat f.add_associated_link("Add Comment", comment, :container => 'something_comments', :partial => 'some_other_partial')
176
+ end
177
+
178
+ @erbout = _erbout
179
+ end
180
+
181
+ should "create link" do
182
+ assert_match ">Add Comment</a>", @erbout
183
+ end
184
+
185
+ should "insert into the bottom of the container specified" do
186
+ assert_match "Insertion.Bottom('something_comments'", @erbout
187
+ end
188
+
189
+ should "wrap the partial in a prototype template" do
190
+ assert_match "new Template", @erbout
191
+ assert_match "evaluate", @erbout
192
+ end
193
+
194
+ should "name the variable correctly" do
195
+ assert_match "attribute_fu_comment_count", @erbout
196
+ end
197
+
198
+ should "produce the following link" do
199
+ # this is a way of testing the whole link
200
+ assert_equal %{
201
+ <a href=\"#\" onclick=\"if (typeof attribute_fu_comment_count == 'undefined') attribute_fu_comment_count = 0;\nnew Insertion.Bottom('something_comments', new Template(null).evaluate({'number': --attribute_fu_comment_count})); return false;\">Add Comment</a>
202
+ }.strip, @erbout
203
+ end
204
+ end
205
+
206
+ context "add associated link with expression parameter" do
207
+ setup do
208
+ comment = @photo.comments.build
209
+
210
+ _erbout = ''
211
+ fields_for(:photo) do |f|
212
+ f.stubs(:render_associated_form).with(comment, :fields_for => {:javascript => true}, :partial => 'some_other_partial')
213
+ _erbout.concat f.add_associated_link("Add Comment", comment, :expression => '$(this).up(".something_comments")', :partial => 'some_other_partial')
214
+ end
215
+
216
+ @erbout = _erbout
217
+ end
218
+
219
+ should "create link" do
220
+ assert_match ">Add Comment</a>", @erbout
221
+ end
222
+
223
+ should "use the javascript expression provided instead of passing the ID in" do
224
+ assert_match "Insertion.Bottom($(this).up(&quot;.something_comments&quot;)", @erbout
225
+ end
226
+
227
+ should "wrap the partial in a prototype template" do
228
+ assert_match "new Template", @erbout
229
+ assert_match "evaluate", @erbout
230
+ end
231
+
232
+ should "name the variable correctly" do
233
+ assert_match "attribute_fu_comment_count", @erbout
234
+ end
235
+
236
+ should "produce the following link" do
237
+ # this is a way of testing the whole link
238
+ assert_equal %{
239
+ <a href=\"#\" onclick=\"if (typeof attribute_fu_comment_count == 'undefined') attribute_fu_comment_count = 0;\nnew Insertion.Bottom($(this).up(&quot;.something_comments&quot;), new Template(null).evaluate({'number': --attribute_fu_comment_count})); return false;\">Add Comment</a>
240
+ }.strip, @erbout
241
+ end
242
+ end
243
+
244
+ context "render_associated_form" do
245
+ setup do
246
+ comment = @photo.comments.build
247
+
248
+ associated_form_builder = mock()
249
+
250
+ _erbout = ''
251
+ fields_for(:photo) do |f|
252
+ f.stubs(:fields_for_associated).yields(associated_form_builder)
253
+ expects(:render).with(:partial => "comment", :locals => { :comment => comment, :f => associated_form_builder })
254
+ _erbout.concat f.render_associated_form(comment).to_s
255
+ end
256
+
257
+ @erbout = _erbout
258
+ end
259
+
260
+ should "extract the correct parameters for render" do
261
+ # assertions in mock
262
+ end
263
+ end
264
+
265
+ context "render_associated_form with specified partial name" do
266
+ setup do
267
+ comment = @photo.comments.build
268
+
269
+ associated_form_builder = mock()
270
+
271
+ _erbout = ''
272
+ fields_for(:photo) do |f|
273
+ f.stubs(:fields_for_associated).yields(associated_form_builder)
274
+ expects(:render).with(:partial => "somewhere/something.html.erb", :locals => { :something => comment, :f => associated_form_builder })
275
+ _erbout.concat f.render_associated_form(comment, :partial => "somewhere/something.html.erb").to_s
276
+ end
277
+
278
+ @erbout = _erbout
279
+ end
280
+
281
+ should "extract the correct parameters for render" do
282
+ # assertions in mock
283
+ end
284
+ end
285
+
286
+ context "render_associated_form with collection" do
287
+ setup do
288
+ associated_form_builder = mock()
289
+ new_comment = Comment.new
290
+ @photo.comments.expects(:build).returns(new_comment).times(3)
291
+ @photo.comments.stubs(:empty?).returns(false)
292
+ @photo.comments.stubs(:first).returns(new_comment)
293
+ @photo.comments.stubs(:map).yields(new_comment)
294
+
295
+ _erbout = ''
296
+ fields_for(:photo) do |f|
297
+ f.stubs(:fields_for_associated).yields(associated_form_builder)
298
+ expects(:render).with(:partial => "comment", :locals => { :comment => new_comment, :f => associated_form_builder })
299
+ _erbout.concat f.render_associated_form(@photo.comments, :new => 3).to_s
300
+ end
301
+
302
+ @erbout = _erbout
303
+ end
304
+
305
+ should "extract the correct parameters for render" do
306
+ # assertions in mock
307
+ end
308
+ end
309
+
310
+ context "render_associated_form with collection that already has a couple of new objects in it" do
311
+ setup do
312
+ associated_form_builder = mock()
313
+ 2.times { @photo.comments.build }
314
+ new_comment = Comment.new
315
+ @photo.comments.expects(:build).returns(new_comment)
316
+ @photo.comments.stubs(:empty?).returns(false)
317
+ @photo.comments.stubs(:first).returns(new_comment)
318
+ @photo.comments.stubs(:map).yields(new_comment)
319
+
320
+ _erbout = ''
321
+ fields_for(:photo) do |f|
322
+ f.stubs(:fields_for_associated).yields(associated_form_builder)
323
+ expects(:render).with(:partial => "comment", :locals => { :comment => new_comment, :f => associated_form_builder })
324
+ _erbout.concat f.render_associated_form(@photo.comments, :new => 3).to_s
325
+ end
326
+
327
+ @erbout = _erbout
328
+ end
329
+
330
+ should "extract the correct parameters for render" do
331
+ # assertions in mock
332
+ end
333
+ end
334
+
335
+ context "render_associated_form with overridden name" do
336
+ setup do
337
+ associated_form_builder = mock()
338
+ comment = @photo.comments.build
339
+
340
+ _erbout = ''
341
+ fields_for(:photo) do |f|
342
+ f.stubs(:fields_for_associated).with(comment, :name => 'something_else').yields(associated_form_builder)
343
+ expects(:render).with(:partial => "something_else", :locals => { :something_else => comment, :f => associated_form_builder })
344
+ _erbout.concat f.render_associated_form(@photo.comments, :name => :something_else).to_s
345
+ end
346
+
347
+ @erbout = _erbout
348
+ end
349
+
350
+ should "render with correct parameters" do
351
+ # assertions in mock
352
+ end
353
+ end
354
+
355
+ private
356
+ def assoc_output(comment, &block)
357
+ _erbout = ''
358
+ fields_for(:photo) do |f|
359
+ _erbout.concat(f.fields_for_associated(comment) do |comment|
360
+ comment.text_field(:author)
361
+ end)
362
+
363
+ _erbout.concat yield(f) if block_given?
364
+ end
365
+
366
+ _erbout
367
+ end
368
+
369
+ def remove_link(*args)
370
+ @erbout = assoc_output(@photo.comments.build) do |f|
371
+ f.fields_for_associated(@photo.comments.build) do |comment|
372
+ comment.remove_link *args
373
+ end
374
+ end
375
+ end
376
+ end