very_best_in_place 2.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (119) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +14 -0
  5. data/CHANGELOG.md +36 -0
  6. data/Gemfile +8 -0
  7. data/README.md +438 -0
  8. data/Rakefile +8 -0
  9. data/best_in_place.gemspec +26 -0
  10. data/lib/assets/javascripts/best_in_place.js +722 -0
  11. data/lib/assets/javascripts/best_in_place.purr.js +10 -0
  12. data/lib/assets/javascripts/jquery.purr.js +161 -0
  13. data/lib/best_in_place.rb +12 -0
  14. data/lib/best_in_place/check_version.rb +8 -0
  15. data/lib/best_in_place/controller_extensions.rb +28 -0
  16. data/lib/best_in_place/display_methods.rb +44 -0
  17. data/lib/best_in_place/engine.rb +8 -0
  18. data/lib/best_in_place/helper.rb +128 -0
  19. data/lib/best_in_place/railtie.rb +7 -0
  20. data/lib/best_in_place/test_helpers.rb +41 -0
  21. data/lib/best_in_place/utils.rb +21 -0
  22. data/lib/best_in_place/version.rb +3 -0
  23. data/spec/helpers/best_in_place_spec.rb +407 -0
  24. data/spec/integration/double_init_spec.rb +34 -0
  25. data/spec/integration/js_spec.rb +959 -0
  26. data/spec/integration/live_spec.rb +40 -0
  27. data/spec/integration/text_area_spec.rb +40 -0
  28. data/spec/spec_helper.rb +23 -0
  29. data/spec/support/retry_on_timeout.rb +10 -0
  30. data/test_app/Gemfile +16 -0
  31. data/test_app/README +256 -0
  32. data/test_app/Rakefile +7 -0
  33. data/test_app/app/assets/images/no.png +0 -0
  34. data/test_app/app/assets/images/red_pen.png +0 -0
  35. data/test_app/app/assets/images/ui-bg_diagonals-thick_18_b81900_40x40.png +0 -0
  36. data/test_app/app/assets/images/ui-bg_diagonals-thick_20_666666_40x40.png +0 -0
  37. data/test_app/app/assets/images/ui-bg_flat_10_000000_40x100.png +0 -0
  38. data/test_app/app/assets/images/ui-bg_glass_100_f6f6f6_1x400.png +0 -0
  39. data/test_app/app/assets/images/ui-bg_glass_100_fdf5ce_1x400.png +0 -0
  40. data/test_app/app/assets/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  41. data/test_app/app/assets/images/ui-bg_gloss-wave_35_f6a828_500x100.png +0 -0
  42. data/test_app/app/assets/images/ui-bg_highlight-soft_100_eeeeee_1x100.png +0 -0
  43. data/test_app/app/assets/images/ui-bg_highlight-soft_75_ffe45c_1x100.png +0 -0
  44. data/test_app/app/assets/images/ui-icons_222222_256x240.png +0 -0
  45. data/test_app/app/assets/images/ui-icons_228ef1_256x240.png +0 -0
  46. data/test_app/app/assets/images/ui-icons_ef8c08_256x240.png +0 -0
  47. data/test_app/app/assets/images/ui-icons_ffd27a_256x240.png +0 -0
  48. data/test_app/app/assets/images/ui-icons_ffffff_256x240.png +0 -0
  49. data/test_app/app/assets/images/yes.png +0 -0
  50. data/test_app/app/assets/javascripts/application.js +35 -0
  51. data/test_app/app/assets/stylesheets/.gitkeep +0 -0
  52. data/test_app/app/assets/stylesheets/jquery-ui-1.8.16.custom.css.erb +357 -0
  53. data/test_app/app/assets/stylesheets/scaffold.css +60 -0
  54. data/test_app/app/assets/stylesheets/style.css.erb +79 -0
  55. data/test_app/app/controllers/admin/users_controller.rb +14 -0
  56. data/test_app/app/controllers/application_controller.rb +3 -0
  57. data/test_app/app/controllers/cuca/cars_controller.rb +16 -0
  58. data/test_app/app/controllers/users_controller.rb +99 -0
  59. data/test_app/app/helpers/application_helper.rb +2 -0
  60. data/test_app/app/helpers/users_helper.rb +29 -0
  61. data/test_app/app/models/cuca/car.rb +5 -0
  62. data/test_app/app/models/user.rb +27 -0
  63. data/test_app/app/views/admin/users/show.html.erb +20 -0
  64. data/test_app/app/views/cuca/cars/show.html.erb +13 -0
  65. data/test_app/app/views/layouts/application.html.erb +14 -0
  66. data/test_app/app/views/users/_form.html.erb +51 -0
  67. data/test_app/app/views/users/double_init.html.erb +72 -0
  68. data/test_app/app/views/users/email_field.html.erb +1 -0
  69. data/test_app/app/views/users/index.html.erb +25 -0
  70. data/test_app/app/views/users/new.html.erb +5 -0
  71. data/test_app/app/views/users/show.html.erb +135 -0
  72. data/test_app/app/views/users/show_ajax.html.erb +12 -0
  73. data/test_app/config.ru +4 -0
  74. data/test_app/config/application.rb +51 -0
  75. data/test_app/config/boot.rb +13 -0
  76. data/test_app/config/database.yml +22 -0
  77. data/test_app/config/environment.rb +5 -0
  78. data/test_app/config/environments/development.rb +25 -0
  79. data/test_app/config/environments/production.rb +49 -0
  80. data/test_app/config/environments/test.rb +35 -0
  81. data/test_app/config/initializers/backtrace_silencers.rb +7 -0
  82. data/test_app/config/initializers/countries.rb +1 -0
  83. data/test_app/config/initializers/default_date_format.rb +2 -0
  84. data/test_app/config/initializers/inflections.rb +10 -0
  85. data/test_app/config/initializers/mime_types.rb +5 -0
  86. data/test_app/config/initializers/secret_token.rb +7 -0
  87. data/test_app/config/initializers/session_store.rb +8 -0
  88. data/test_app/config/locales/en.yml +5 -0
  89. data/test_app/config/routes.rb +20 -0
  90. data/test_app/db/migrate/20101206205922_create_users.rb +18 -0
  91. data/test_app/db/migrate/20101212170114_add_receive_email_to_user.rb +9 -0
  92. data/test_app/db/migrate/20110115204441_add_description_to_user.rb +9 -0
  93. data/test_app/db/migrate/20111210084202_add_favorite_color_to_users.rb +5 -0
  94. data/test_app/db/migrate/20111210084251_add_favorite_books_to_users.rb +5 -0
  95. data/test_app/db/migrate/20111217215935_add_birth_date_to_users.rb +5 -0
  96. data/test_app/db/migrate/20111224181356_add_money_to_user.rb +5 -0
  97. data/test_app/db/migrate/20120513003308_create_cars.rb +11 -0
  98. data/test_app/db/migrate/20120607172609_add_favorite_movie_to_users.rb +5 -0
  99. data/test_app/db/migrate/20120616170454_add_money_proc_to_users.rb +6 -0
  100. data/test_app/db/migrate/20120620165212_add_height_to_user.rb +5 -0
  101. data/test_app/db/schema.rb +40 -0
  102. data/test_app/db/seeds.rb +19 -0
  103. data/test_app/doc/README_FOR_APP +2 -0
  104. data/test_app/lib/tasks/.gitkeep +0 -0
  105. data/test_app/lib/tasks/cron.rake +7 -0
  106. data/test_app/public/404.html +26 -0
  107. data/test_app/public/422.html +26 -0
  108. data/test_app/public/500.html +26 -0
  109. data/test_app/public/favicon.ico +0 -0
  110. data/test_app/public/robots.txt +5 -0
  111. data/test_app/script/rails +6 -0
  112. data/test_app/test/fixtures/users.yml +17 -0
  113. data/test_app/test/functional/users_controller_test.rb +49 -0
  114. data/test_app/test/performance/browsing_test.rb +9 -0
  115. data/test_app/test/test_helper.rb +13 -0
  116. data/test_app/test/unit/helpers/users_helper_test.rb +4 -0
  117. data/test_app/test/unit/user_test.rb +8 -0
  118. data/test_app/vendor/plugins/.gitkeep +0 -0
  119. metadata +241 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: eaaf318d991e38ba9d062f3dbb953a06a11dedf6
4
+ data.tar.gz: c6e06502b482bfe92afa195c609728e51cd2d4e8
5
+ SHA512:
6
+ metadata.gz: 8743f87695ee57e164d06e22373c8e44780e3a92cec0d2e07e832a5c0776c8ea93259a531a06a5d481c7207b838a20d6d7a83686c260b658326849e90b84831d
7
+ data.tar.gz: bc56f30b174eee01c598507bc2ea00f504fe2602881cfd99bcd7dcb96f9b192199e02a95bfffb2f8fa72f8e52b38f9c871f4bdd7abcd1672d45f6647f66fc279
@@ -0,0 +1,11 @@
1
+ .DS_Store
2
+ .bundle
3
+ pkg/*
4
+
5
+ Gemfile.lock
6
+ test_app/.bundle
7
+ test_app/db/*.sqlite3
8
+ test_app/log/*.log
9
+ test_app/tmp/**/*
10
+
11
+ .rvmrc
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour
@@ -0,0 +1,14 @@
1
+ rvm:
2
+ - 1.9.2
3
+ - 1.9.3
4
+
5
+ env: "RAILS_ENV=test DISPLAY=:99.0"
6
+
7
+ before_script:
8
+ - "sh -c 'cd test_app && bundle && bundle exec rake db:drop db:migrate'"
9
+ - "sh -e /etc/init.d/xvfb start"
10
+
11
+ branches:
12
+ only:
13
+ - master
14
+ - rails-3.0
@@ -0,0 +1,36 @@
1
+ #Changelog
2
+
3
+ ##Master branch (and part of the Rails 3.0 branch)
4
+ - v.0.1.0 Initial commit
5
+ - v.0.1.2 Fixing errors in collections (taken value[0] instead of index) and fixing test_app controller responses
6
+ - v.0.1.3 Bug in Rails Helper. Key wrongly considered an Integer.
7
+ - v.0.1.4 Adding two new parameters for further customization urlObject and nilValue and making input update on blur.
8
+ - v.0.1.5 **Attention: this release is not backwards compatible**. Changing params from list to option hash, helper's refactoring,
9
+ fixing bug with objects inside namespaces, adding feature for passing an external activator handler as param. Adding feature
10
+ of key ESCAPE for destroying changes before they are made permanent (in inputs and textarea).
11
+ - v.0.1.6-0.1.7 Avoiding request when the input is not modified and allowing the user to not sanitize input data.
12
+ - v.0.1.8 jslint compliant, sanitizing tags in the gem, getting right csrf params, controlling size of textarea (elastic script, for autogrowing textarea)
13
+ - v.0.1.9 Adding elastic autogrowing textareas
14
+ - v.1.0.0 Setting RSpec and Capybara up, and adding some utilities. Mantaining some HTML attributes. Fix a respond_with bug (thanks, @moabite). Triggering ajax:success when ajax call is complete (thanks, @indrekj). Setting up Travis CI. Updated for Rails 3.1.
15
+ - v.1.0.1 Fixing a double initialization bug
16
+ - v.1.0.2 New bip_area text helper to work with text areas.
17
+ - v.1.0.3 replace apostrophes in collection with corresponding HTML entity,
18
+ thanks @taavo. Implemented `:display_as` option and adding
19
+ `respond_with_bip` to be used in the controller.
20
+ - v.1.0.4 Depend on ActiveModel instead of ActiveRecord (thanks,
21
+ @skinnyfit). Added date type (thanks @taavo). Added new feature:
22
+ display_with.
23
+ - v.1.0.5 Fix a bug involving quotes (thanks @ygoldshtrakh). Minor fixes
24
+ by @bfalling. Add object name option (thanks @nicholassm). Check
25
+ version of Rails before booting. Minor fixes.
26
+ - v.1.0.6 Fix issue with display_with. Update test_app to 3.2.
27
+ - v.1.1.0 Changed $ by jQuery for compatibility (thanks @tschmitz), new
28
+ events for 'deactivate' (thanks @glebtv), added new 'data' attribute
29
+ to BIP's span (thanks @straydogstudio), works with dynamically added
30
+ elements to the page (thanks @enriclluelles), added object detection to
31
+ the 'path' parameter and some more bugfixes.
32
+
33
+ ##Rails 3.0 branch only
34
+ - v.0.2.0 Added RSpec and Capybara setup, and some tests. Fix countries map syntax, Allowing href and some other HTML attributes. Adding Travis CI too. Added the best_in_place_if option. Added ajax:success trigger, thanks to @indrekj.
35
+ - v.0.2.1 Fixing double initialization bug.
36
+ - v.0.2.2 New bip_area text helper.
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in best_in_place.gemspec
4
+ gemspec
5
+
6
+ gem 'sqlite3'
7
+ gem 'jquery-rails'
8
+ gem 'rdiscount'
@@ -0,0 +1,438 @@
1
+ # Best In Place
2
+ [![Build Status](https://secure.travis-ci.org/bernat/best_in_place.png)](http://travis-ci.org/bernat/best_in_place)
3
+ **The Unobtrusive in Place editing solution**
4
+
5
+
6
+ ##Description
7
+
8
+ **Best in Place** is a jQuery based AJAX Inplace-Editor that takes profit of RESTful server-side controllers to allow users to edit stuff with
9
+ no need of forms. If the server have standard defined REST methods, particularly those to UPDATE your objects (HTTP PUT), then by adding the
10
+ Javascript file to the application it is making all the fields with the proper defined classes to become user in-place editable.
11
+
12
+ The editor works by PUTting the updated value to the server and GETting the updated record afterwards to display the updated value.
13
+
14
+ [**SEE DEMO**](http://bipapp.heroku.com/)
15
+
16
+ ---
17
+
18
+ ##Features
19
+
20
+ - Compatible with text **inputs**
21
+ - Compatible with **textarea**
22
+ - Compatible with **select** dropdown with custom collections
23
+ - Compatible with custom boolean values (same usage of **checkboxes**)
24
+ - Compatible with **jQuery UI Datepickers**
25
+ - Sanitize HTML and trim spaces of user's input on user's choice
26
+ - Displays server-side **validation** errors
27
+ - Allows external activator
28
+ - Allows optional, configurable OK and Cancel buttons for inputs and textareas
29
+ - ESC key destroys changes (requires user confirmation)
30
+ - Autogrowing textarea
31
+ - Helper for generating the best_in_place field only if a condition is satisfied
32
+ - Provided test helpers to be used in your integration specs
33
+ - Custom display methods using a method from your model or an existing rails
34
+ view helper
35
+
36
+ ##Usage of Rails 3 Gem
37
+
38
+ ###best_in_place
39
+ **best_in_place object, field, OPTIONS**
40
+
41
+ Params:
42
+
43
+ - **object** (Mandatory): The Object parameter represents the object itself you are about to modify
44
+ - **field** (Mandatory): The field (passed as symbol) is the attribute of the Object you are going to display/edit.
45
+
46
+ Options:
47
+
48
+ - **:type** It can be only [:input, :textarea, :select, :checkbox, :date (>= 1.0.4)] or if undefined it defaults to :input.
49
+ - **:collection**: In case you are using the :select type then you must specify the collection of values it takes. In case you are
50
+ using the :checkbox type you can specify the two values it can take, or otherwise they will default to Yes and No.
51
+ - **:path**: URL to which the updating action will be sent. If not defined it defaults to the :object path.
52
+ - **:nil**: The nil param defines the content displayed in case no value is defined for that field. It can be something like "click me to edit".
53
+ If not defined it will show *"-"*.
54
+ - **:activator**: Is the DOM object that can activate the field. If not defined the user will making editable by clicking on it.
55
+ - **:ok_button**: (Inputs and textareas only) If set to a string, then an OK button will be shown with the string as its label, replacing save on blur.
56
+ - **:cancel_button**: (Inputs and textareas only) If set to a string, then a Cancel button will be shown with the string as its label.
57
+ - **:sanitize**: True by default. If set to false the input/textarea will accept html tags.
58
+ - **:html_attrs**: Hash of html arguments, such as maxlength, default-value etc.
59
+ - **:inner_class**: Class that is set to the rendered form.
60
+ - **:display_as**: A model method which will be called in order to display
61
+ this field.
62
+ - **:object_name**: Used for overriding the default params key used for the object (the data-object attribute). Useful for e.g. STI scenarios where best_in_place should post to a common controller for different models.
63
+ - **:data**: Hash of custom data attributes to be added to span. Can be used to provide data to the ajax:success callback.
64
+ - **:classes**: Additional classes to apply to the best_in_place span. Accepts either a string or Array of strings
65
+
66
+ ###best_in_place_if
67
+ **best_in_place_if condition, object, field, OPTIONS**
68
+
69
+ It allows us to use best_in_place only if the first new parameter, a
70
+ condition, is satisfied. Specifically:
71
+
72
+ * Will show a normal best_in_place if the condition is satisfied
73
+ * Will only show the attribute from the instance if the condition is not satisfied
74
+
75
+ Say we have something like
76
+
77
+ <%= best_in_place_if condition, @user, :name, :type => :input %>
78
+
79
+ In case *condition* is satisfied, the outcome will be just the same as:
80
+
81
+ <%= best_in_place @user, :name, :type => :input %>
82
+
83
+ Otherwise, we will have the same outcome as:
84
+
85
+ <%= @user.name %>
86
+
87
+ It is a very useful feature to use with, for example, [Ryan Bates](https://github.com/ryanb)' [CanCan](https://github.com/ryanb/cancan), so we only allow BIP edition if the current user has permission to do it.
88
+
89
+ ---
90
+
91
+ ##TestApp and examples
92
+ A [test_app](https://github.com/bernat/best_in_place/tree/master/test_app) was created, and can be seen in action in a [running demo on heroku](http://bipapp.heroku.com).
93
+
94
+ Examples (code in the views):
95
+
96
+ ### Input
97
+
98
+ <%= best_in_place @user, :name, :type => :input %>
99
+
100
+ <%= best_in_place @user, :name, :type => :input, :nil => "Click me to add content!" %>
101
+
102
+ ### Textarea
103
+
104
+ <%= best_in_place @user, :description, :type => :textarea %>
105
+
106
+ <%= best_in_place @user, :favorite_books, :type => :textarea, :ok_button => 'Save', :cancel_button => 'Cancel' %>
107
+
108
+ ### Select
109
+
110
+ <%= best_in_place @user, :country, :type => :select, :collection => [[1, "Spain"], [2, "Italy"], [3, "Germany"], [4, "France"]] %>
111
+
112
+ Of course it can take an instance or global variable for the collection, just remember the structure `[[key, value], [key, value],...]`.
113
+ The key can be a string or an integer.
114
+
115
+ ### Checkbox
116
+
117
+ <%= best_in_place @user, :receive_emails, :type => :checkbox, :collection => ["No, thanks", "Yes, of course!"] %>
118
+
119
+ The first value is always the negative boolean value and the second the positive. Structure: `["false value", "true value"]`.
120
+ If not defined, it will default to *Yes* and *No* options.
121
+
122
+ ### Date
123
+
124
+ <%= best_in_place @user, :birth_date, :type => :date %>
125
+
126
+ With the :date type the input field will be initialized as a datepicker input.
127
+ In order to provide custom options to the datepicker initialization you must
128
+ prepare a `$.datepicker.setDefaults` call with the preferences of your choice.
129
+
130
+ More information about datepicker and setting defaults can be found
131
+ [here](http://docs.jquery.com/UI/Datepicker/$.datepicker.setDefaults)
132
+
133
+ ## Controller response with respond_with_bip
134
+
135
+ Best in place provides a utility method you should use in your controller in
136
+ order to provide the response that is expected by the javascript side, using
137
+ the :json format. This is a simple example showing an update action using it:
138
+
139
+ def update
140
+ @user = User.find params[:id]
141
+
142
+ respond_to do |format|
143
+ if @user.update_attributes(params[:user])
144
+ format.html { redirect_to(@user, :notice => 'User was successfully updated.') }
145
+ format.json { respond_with_bip(@user) }
146
+ else
147
+ format.html { render :action => "edit" }
148
+ format.json { respond_with_bip(@user) }
149
+ end
150
+ end
151
+ end
152
+
153
+
154
+ ## Custom display methods
155
+
156
+ ### Using `display_as`
157
+
158
+ As of best in place 1.0.3 you can use custom methods in your model in order to
159
+ decide how a certain field has to be displayed. You can write something like:
160
+
161
+ = best_in_place @user, :description, :type => :textarea, :display_as => :mk_description
162
+
163
+ Then instead of using `@user.description` to show the actual value, best in
164
+ place will call `@user.mk_description`. This can be used for any kind of
165
+ custom formatting, text with markdown, etc...
166
+
167
+ ### Using `display_with`
168
+
169
+ In practice the most common situation is when you want to use an existing
170
+ helper to render the attribute, like `number_to_currency` or `simple_format`.
171
+ As of version 1.0.4 best in place provides this feature using the
172
+ `display_with` option. You can use it like this:
173
+
174
+ = best_in_place @user, :money, :display_with => :number_to_currency
175
+
176
+ If you want to pass further arguments to the helper you can do it providing an
177
+ additional `helper_options` hash:
178
+
179
+ = best_in_place @user, :money, :display_with => :number_to_currency, :helper_options => {:unit => "€"}
180
+
181
+ You can also pass in a proc or lambda like this:
182
+
183
+ = best_in_place @post, :body, :display_with => lambda { |v| textilize(v).html_safe }
184
+
185
+ ## Ajax success callback
186
+
187
+ ### Binding to ajax:success
188
+
189
+ The 'ajax:success' event is triggered upon success. Use bind:
190
+
191
+ $('.best_in_place').bind("ajax:success", function(){$(this).closest('tr').effect('highlight'));});
192
+
193
+ To bind a callback that is specific to a particular field, use the 'classes' option in the helper method and
194
+ then bind to that class.
195
+
196
+ <%= best_in_place @user, :name, :classes => 'highlight_on_success' %>
197
+ <%= best_in_place @user, :mail, :classes => 'bounce_on_success' %>
198
+
199
+ $('.highlight_on_success').bind("ajax:success", function(){$(this).closest('tr').effect('highlight'));});
200
+ $('.bounce_on_success').bind("ajax:success", function(){$(this).closest('tr').effect('bounce'));});
201
+
202
+ ### Providing data to the callback
203
+
204
+ Use the :data option to add HTML5 data attributes to the best_in_place span. For example, in your view:
205
+
206
+ <%= best_in_place @user, :name, :data => {:user_name => @user.name} %>
207
+
208
+ And in your javascript:
209
+
210
+ $('.best_in_place').bind("ajax:success", function(){ alert('Name updated for '+$(this).data('userName')); });
211
+
212
+ ##Non Active Record environments
213
+ We are not planning to support other ORMs apart from Active Record, at least for now. So, you can perfectly consider the following workaround as *the right way* until a specific implementation is done for your ORM.
214
+
215
+ Best In Place automatically assumes that Active Record is the ORM you are using. However, this might not be your case, as you might use another ORM (or not ORM at all for that case!). Good news for you: even in such situation Best In Place can be used!
216
+
217
+ Let's setup an example so we can illustrate how to use Best In Place too in a non-ORM case. Imagine you have an awesome ice cream shop, and you have a model representing a single type of ice cream. The IceCream model has a name, a description, a... nevermind. The thing is that it also has a stock, which is a combination of flavour and size. A big chocolate ice cream (yummy!), a small paella ice cream (...really?), and so on. Shall we see some code?
218
+
219
+ class IceCream < ActiveRecord::Base
220
+ serialize :stock, Hash
221
+
222
+ # consider the get_stock and set_stock methods are already defined
223
+ end
224
+
225
+ Imagine we want to have a grid showing all the combinations of flavour and size and, for each combination, an editable stock. Since the stock for a flavour and a size is not a single and complete model attribute, we cannot use Best In Place *directly*. But we can set it up with an easy workaround.
226
+
227
+ In the view, we'd do:
228
+
229
+ // @ice_cream is already available
230
+ - flavours = ... // get them somewhere
231
+ - sizes = ... // get them somewhere
232
+ %table
233
+ %tr
234
+ - ([""] + flavours).each do |flavour|
235
+ %th= flavour
236
+ - sizes.each do |size|
237
+ %tr
238
+ %th= size
239
+ - flavours.each do |flavour|
240
+ - v = @ice_cream.get_stock(:flavour => flavour, :size => size)
241
+ %td= best_in_place v, :to_i, :type => :input, :path => set_stock_ice_cream_path(:flavour => flavour, :size => size)
242
+
243
+ Now we need a route to which send the stock updates:
244
+
245
+ TheAwesomeIceCreamShop::Application.routes.draw do
246
+ ...
247
+
248
+ resources :ice_creams, :only => :none do
249
+ member do
250
+ put :set_stock
251
+ end
252
+ end
253
+
254
+ ...
255
+ end
256
+
257
+ And finally we need a controller:
258
+
259
+
260
+ class IceCreamsController < ApplicationController::Base
261
+ respond_to :html, :json
262
+
263
+ ...
264
+
265
+ def set_stock
266
+ flavour = params[:flavour]
267
+ size = params[:size]
268
+ new_stock = (params["fixnum"] || {})["to_i"]
269
+
270
+ @ice_cream.set_stock(new_stock, { :flavour => flavour, :size => size })
271
+ if @ice_cream.save
272
+ head :ok
273
+ else
274
+ render :json => @ice_cream.errors.full_messages, :status => :unprocessable_entity
275
+ end
276
+ end
277
+
278
+ ...
279
+
280
+ end
281
+
282
+ And this is how it is done!
283
+
284
+ ---
285
+
286
+ ##Test Helpers
287
+ Best In Place has also some helpers that may be very useful for integration testing. Since it might very common to test some views using Best In Place, some helpers are provided to ease it.
288
+
289
+ As of now, a total of four helpers are available. There is one for each of the following BIP types: a plain text input, a textarea, a boolean input and a selector. Its function is to simulate the user's action of filling such fields.
290
+
291
+ These four helpers are listed below:
292
+
293
+ * **bip_area(model, attr, new_value)**
294
+ * **bip_text(model, attr, new_value)**
295
+ * **bip_bool(model, attr)**
296
+ * **bip_select(model, attr, name)**
297
+
298
+ The parameters are defined here (some are method-specific):
299
+
300
+ * **model**: the model to which this action applies.
301
+ * **attr**: the attribute of the model to which this action applies.
302
+ * **new_value** (only **bip_area** and **bip_text**): the new value with which to fill the BIP field.
303
+ * **name** (only **bip_select**): the name to select from the dropdown selector.
304
+
305
+ ---
306
+
307
+ ##Installation
308
+
309
+ ###Rails 3.1 and higher
310
+
311
+ Installing *best_in_place* is very easy and straight-forward, even more
312
+ thanks to Rails 3.1. Just begin including the gem in your Gemfile:
313
+
314
+ gem "best_in_place"
315
+
316
+ After that, specify the use of the jquery and best in place
317
+ javascripts in your application.js, and optionally specify jquery-ui if
318
+ you want to use jQuery UI datepickers:
319
+
320
+ //= require jquery
321
+ //= require jquery-ui
322
+ //= require best_in_place
323
+
324
+ If you want to use jQuery UI datepickers, you should also install and
325
+ load your preferred jquery-ui CSS file and associated assets.
326
+
327
+ Then, just add a binding to prepare all best in place fields when the document is ready:
328
+
329
+ $(document).ready(function() {
330
+ /* Activating Best In Place */
331
+ jQuery(".best_in_place").best_in_place();
332
+ });
333
+
334
+ You are done!
335
+
336
+ ###Rails 3.0 and lower
337
+
338
+ Installing *best_in_place* for Rails 3.0 or below is a little bit
339
+ different, since the master branch is specifically updated for Rails
340
+ 3.1. But don't be scared, you'll be fine!
341
+
342
+ Rails 3.0 support will be held in the 0.2.X versions, but we have planned not to continue developing for this version of Rails. Nevertheless, you can by implementing what you want and sending us a pull request.
343
+
344
+ First, add the gem's 0.2 version in the Gemfile:
345
+
346
+ gem "best_in_place", "~> 0.2.0"
347
+
348
+ After that, install and load all the javascripts from the folder
349
+ **/public/javascripts** in your layouts. They have to be in the order:
350
+
351
+ * jquery
352
+ * **best_in_place**
353
+
354
+ You can automatize this installation by doing
355
+
356
+ rails g best_in_place:setup
357
+
358
+ If you want to use jQuery UI datepickers, you should also install and
359
+ load jquery-ui.js as well as your preferred jquery-ui CSS file and
360
+ associated assets.
361
+
362
+ Finally, as for Rails 3.1, just add a binding to prepare all best in place fields when the document is ready:
363
+
364
+ $(document).ready(function() {
365
+ /* Activating Best In Place */
366
+ jQuery(".best_in_place").best_in_place();
367
+ });
368
+
369
+ ---
370
+
371
+ ## Notification
372
+
373
+ Sometimes your in-place updates will fail due to validation or for some other reason. In such case, you'll want to notify the user somehow. **Best in Place** supports doing so through the best_in_place:error event, and has built-in support for notification via jquery.purr, right out of the box.
374
+
375
+ To opt into the jquery.purr error notification, just add best_in_place.purr to your javascripts, as described below. If you'd like to develop your own custom form of error notification, you can use best_in_place.purr as an example to guide you.
376
+
377
+ ###Rails 3.1 and higher
378
+
379
+ It's as simple as adding:
380
+
381
+ //= require best_in_place.purr
382
+
383
+ ###Rails 3.0 and lower
384
+
385
+ You'll have to load the following additional javascripts, in this order, after loading jquery and **best_in_place**:
386
+
387
+ * jquery.purr
388
+ * **best_in_place.purr**
389
+
390
+ ---
391
+
392
+ ## Security
393
+
394
+ If the script is used with the Rails Gem no html tags will be allowed unless the sanitize option is set to true, in that case only the tags [*b i u s a strong em p h1 h2 h3 h4 h5 ul li ol hr pre span img*] will be allowed. If the script is used without the gem and with frameworks other than Rails, then you should make sure you are providing the csrf authenticity params as meta tags and you should always escape undesired html tags such as script, object and so forth.
395
+
396
+ <meta name="csrf-param" content="authenticity_token"/>
397
+ <meta name="csrf-token" content="YOUR UNIQUE TOKEN HERE"/>
398
+
399
+ ---
400
+
401
+ ##TODO
402
+
403
+ - Client Side Validation definitions
404
+ - Accepting more than one handler to activate best_in_place fields
405
+
406
+ ---
407
+
408
+ ## Development
409
+
410
+ Fork the project on [github](https://github.com/bernat/best_in_place 'bernat / best_in_place on Github')
411
+
412
+ $ git clone <<your fork>
413
+ $ cd best_in_place
414
+ $ bundle
415
+
416
+ ### Prepare the test app
417
+
418
+ $ cd test_app
419
+ $ bundle
420
+ $ bundle exec rake db:test:prepare
421
+ $ cd ..
422
+
423
+ ### Run the specs
424
+
425
+ $ bundle exec rspec spec/
426
+
427
+ ### Bundler / gem troubleshooting
428
+
429
+ - make sure you've run the bundle command for both the app and test_app!
430
+ - run bundle update <<gem name> (in the right place) for any gems that are causing issues
431
+
432
+ ---
433
+
434
+ ##Authors, License and Stuff
435
+
436
+ Code by [Bernat Farrero](http://bernatfarrero.com) from [Itnig Web Services](http://itnig.net) (it was based on the [original project](http://github.com/janv/rest_in_place/) of Jan Varwig) and released under [MIT license](http://www.opensource.org/licenses/mit-license.php).
437
+
438
+ Many thanks to the contributors: [Roger Campos](http://github.com/rogercampos), [Jack Senechal](https://github.com/jacksenechal) and [Albert Bellonch](https://github.com/albertbellonch).