selections 0.0.1 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. data/.gitignore +18 -0
  2. data/CHANGELOG.md +3 -0
  3. data/Gemfile +4 -0
  4. data/{MIT-LICENSE → LICENSE.txt} +4 -2
  5. data/README.md +237 -0
  6. data/Rakefile +3 -29
  7. data/lib/selections.rb +22 -6
  8. data/lib/selections/belongs_to_selection.rb +20 -0
  9. data/lib/selections/form_builder_extensions.rb +86 -0
  10. data/lib/selections/selectable.rb +125 -0
  11. data/lib/selections/version.rb +1 -1
  12. data/selections.gemspec +38 -0
  13. data/spec/selections/selectable_spec.rb +220 -0
  14. data/spec/selections/selections_tag_spec.rb +203 -0
  15. data/spec/spec_helper.rb +30 -21
  16. metadata +99 -177
  17. data/README.rdoc +0 -3
  18. data/app/assets/javascripts/selections/application.js +0 -9
  19. data/app/assets/javascripts/selections/selections.js +0 -2
  20. data/app/assets/stylesheets/scaffold.css +0 -56
  21. data/app/assets/stylesheets/selections/application.css +0 -7
  22. data/app/assets/stylesheets/selections/selections.css +0 -4
  23. data/app/controllers/selections/application_controller.rb +0 -4
  24. data/app/controllers/selections/selections_controller.rb +0 -45
  25. data/app/helpers/selections/application_helper.rb +0 -4
  26. data/app/helpers/selections/selectors_helper.rb +0 -4
  27. data/app/models/selections/selection.rb +0 -83
  28. data/app/views/layouts/selections/application.html.erb +0 -1
  29. data/app/views/selections/selections/_form.html.erb +0 -41
  30. data/app/views/selections/selections/edit.html.erb +0 -6
  31. data/app/views/selections/selections/index.html.erb +0 -33
  32. data/app/views/selections/selections/new.html.erb +0 -5
  33. data/app/views/selections/selections/show.html.erb +0 -35
  34. data/config/initializers/selections.rb +0 -1
  35. data/config/routes.rb +0 -5
  36. data/db/migrate/20120114024459_create_selections_selections.rb +0 -15
  37. data/lib/selections/engine.rb +0 -5
  38. data/lib/selections/selection_select.rb +0 -24
  39. data/lib/tasks/selections_tasks.rake +0 -4
  40. data/spec/controllers/companies_controller_spec.rb +0 -10
  41. data/spec/controllers/selections/selections_controller_spec.rb +0 -165
  42. data/spec/dummy/Rakefile +0 -7
  43. data/spec/dummy/app/assets/javascripts/application.js +0 -9
  44. data/spec/dummy/app/assets/javascripts/companies.js +0 -2
  45. data/spec/dummy/app/assets/stylesheets/application.css +0 -7
  46. data/spec/dummy/app/assets/stylesheets/companies.css +0 -4
  47. data/spec/dummy/app/assets/stylesheets/scaffold.css +0 -56
  48. data/spec/dummy/app/controllers/application_controller.rb +0 -2
  49. data/spec/dummy/app/controllers/companies_controller.rb +0 -83
  50. data/spec/dummy/app/helpers/application_helper.rb +0 -2
  51. data/spec/dummy/app/helpers/companies_helper.rb +0 -2
  52. data/spec/dummy/app/models/company.rb +0 -7
  53. data/spec/dummy/app/views/companies/_form.html.erb +0 -3
  54. data/spec/dummy/app/views/companies/edit.html.erb +0 -4
  55. data/spec/dummy/app/views/companies/index.html.erb +0 -27
  56. data/spec/dummy/app/views/companies/new.html.erb +0 -5
  57. data/spec/dummy/app/views/companies/show.html.erb +0 -20
  58. data/spec/dummy/app/views/layouts/application.html.erb +0 -11
  59. data/spec/dummy/config.ru +0 -4
  60. data/spec/dummy/config/application.rb +0 -45
  61. data/spec/dummy/config/boot.rb +0 -10
  62. data/spec/dummy/config/database.yml +0 -25
  63. data/spec/dummy/config/environment.rb +0 -5
  64. data/spec/dummy/config/environments/development.rb +0 -30
  65. data/spec/dummy/config/environments/production.rb +0 -60
  66. data/spec/dummy/config/environments/test.rb +0 -42
  67. data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -7
  68. data/spec/dummy/config/initializers/inflections.rb +0 -10
  69. data/spec/dummy/config/initializers/mime_types.rb +0 -5
  70. data/spec/dummy/config/initializers/secret_token.rb +0 -7
  71. data/spec/dummy/config/initializers/session_store.rb +0 -8
  72. data/spec/dummy/config/initializers/wrap_parameters.rb +0 -14
  73. data/spec/dummy/config/locales/en.yml +0 -5
  74. data/spec/dummy/config/routes.rb +0 -6
  75. data/spec/dummy/db/development.sqlite3 +0 -0
  76. data/spec/dummy/db/migrate/20120114125226_create_selections_selections.rb +0 -15
  77. data/spec/dummy/db/migrate/20120115055119_create_companies.rb +0 -12
  78. data/spec/dummy/db/schema.rb +0 -38
  79. data/spec/dummy/db/test.sqlite3 +0 -0
  80. data/spec/dummy/log/development.log +0 -94
  81. data/spec/dummy/log/test.log +0 -26360
  82. data/spec/dummy/public/404.html +0 -26
  83. data/spec/dummy/public/422.html +0 -26
  84. data/spec/dummy/public/500.html +0 -26
  85. data/spec/dummy/public/favicon.ico +0 -0
  86. data/spec/dummy/script/rails +0 -6
  87. data/spec/helpers/selections/selections_helper_spec.rb +0 -15
  88. data/spec/models/company_spec.rb +0 -7
  89. data/spec/models/selections/selection_spec.rb +0 -219
  90. data/spec/routing/selections/selections_routing_spec.rb +0 -35
  91. data/spec/support/controller_route_fix.rb +0 -33
  92. data/spec/support/factories/company_factory.rb +0 -5
  93. data/spec/support/factories/selection_factory.rb +0 -5
  94. data/spec/views/companies/edit.html.erb_spec.rb +0 -76
  95. data/spec/views/companies/new.html.erb_spec.rb +0 -78
  96. data/spec/views/selections/selections/edit.html.erb_spec.rb +0 -28
  97. data/spec/views/selections/selections/index.html.erb_spec.rb +0 -40
  98. data/spec/views/selections/selections/new.html.erb_spec.rb +0 -28
  99. data/spec/views/selections/selections/show.html.erb_spec.rb +0 -30
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .idea/
@@ -0,0 +1,3 @@
1
+ ## 0.0.1
2
+
3
+ * Initial release
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in selections.gemspec
4
+ gemspec
@@ -1,4 +1,6 @@
1
- Copyright 2012 YOURNAME
1
+ Copyright (c) 2012 Nigel Rausch
2
+
3
+ MIT License
2
4
 
3
5
  Permission is hereby granted, free of charge, to any person obtaining
4
6
  a copy of this software and associated documentation files (the
@@ -17,4 +19,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
19
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
20
  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
21
  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.
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,237 @@
1
+ # Selections
2
+
3
+ Selection list management and form and view helpers.
4
+
5
+ ##Key Features
6
+
7
+ * Manages one table to hold all selections items/ dropdown lists ( tree )
8
+ * Dynamic lookup to find parent or children ( eg. Selection.priorities )
9
+ * Form helper to display lists ( eg. f.selections :priorities )
10
+ * Model helpers for joining tables ( eg. belongs_to_selection :priority )
11
+ * Handling of archived items ( displaying if selected only )
12
+ * Ordering of lists based on alpha or numbered
13
+ * Default item handling
14
+
15
+ ## Installation
16
+
17
+ Add this line to your application's Gemfile:
18
+
19
+ gem 'selections'
20
+
21
+ And then execute:
22
+
23
+ $ bundle
24
+
25
+ Or install it yourself as:
26
+
27
+ $ gem install selections
28
+
29
+ ## Usage
30
+
31
+ First, you need to configure your selection model. We typically use `Selection` for this (although you
32
+ can change the name), and should be generated such as:
33
+
34
+ ```ruby
35
+ rails generate model Selection name parent_id:integer system_code position_value:integer is_default:boolean is_system:boolean archived_at:datetime
36
+ ```
37
+
38
+ ### Model
39
+ And next, edit this class to look like:
40
+
41
+ ```ruby
42
+ class Selection < ActiveRecord::Base
43
+ selectable
44
+ end
45
+ ```
46
+
47
+ Selections table can contain one or many lists, it uses the acts_as_tree so each root is a new list
48
+ meta example: (see below for example YAML file)
49
+ - priority
50
+ - high
51
+ - medium
52
+ - low
53
+ - user_role
54
+ - admin
55
+ - owner
56
+ - user
57
+
58
+ From the rails console it is be possible to access these items directly using dynamic lookups
59
+
60
+ ```ruby
61
+ Selection.priority => returns the parent row
62
+ Selection.user_role
63
+ ```
64
+
65
+ Dynamic lookups support pluralization and will then return the children
66
+
67
+ ```ruby
68
+ Selection.priorities => [high,med,low] records
69
+ ```
70
+
71
+ #### Form Helper
72
+
73
+ if we had a controller for Ticket model with fields of
74
+ - name
75
+ - priority_id
76
+
77
+ within the _form.html.erb just use the selections helper method
78
+
79
+ ```ruby
80
+ <%= form_for(@ticket) do |f| %>
81
+
82
+ <div>
83
+ <%= f.label :name %><br />
84
+ <%= f.text_field :name %>
85
+ </div>
86
+
87
+ <div>
88
+ <%= f.label :priority %><br />
89
+ <%= f.selections :priority %>
90
+ </div>
91
+
92
+ <div>
93
+ <%= f.submit %>
94
+ </div>
95
+ <% end %>
96
+ ```
97
+
98
+ If you have naming conflicts/duplicates eg. user categories and ticket categories within in the selections name the parent/system_code
99
+ user_category & ticket_category. The foreign key within the user and ticket can both be category_id and the form_helper will still be
100
+
101
+ user form
102
+ ```ruby
103
+ f.selections :category
104
+ ```
105
+ this will automatically look up the user_category selections.
106
+
107
+ If you have a selection named differently to the foreign key eg the foreign key is variety_id, you can use a system_code option
108
+
109
+ ```ruby
110
+ f.selections :variety, :system_code => :category
111
+ ```
112
+
113
+ Next, you need to tell models that have a selectable association. These are `belongs_to` associations
114
+ which pull their values from the selections model. Assuming you have a `Ticket` model with a foreign key of priority_id,
115
+ you can set this up like so:
116
+
117
+ ```ruby
118
+ class Ticket < ActiveRecord::Base
119
+
120
+ belongs_to_selection :priority
121
+
122
+ end
123
+ ```
124
+
125
+ From an instance of a ticket within a view the belongs_to selection will return string (to_s).
126
+ eg: show.html.erb
127
+
128
+
129
+ ```ruby
130
+ ticket.priority.try(:name) # don't need to do this
131
+
132
+ ticket.priority # will default to return name
133
+ ```
134
+
135
+ ### Automatic Features
136
+ #### Include Blank
137
+
138
+ In a new form the selections list will have blank top row unless a default item is set in the selections eg. Medium Priority, then there
139
+ will be no blank row and the default item will be selected
140
+
141
+ When editing a form, by default the blank row will not be displayed
142
+
143
+ #### Archived Item
144
+
145
+ On a new form items that are archived in Selections will not appear in the selection list. When editing an existing record the list will only
146
+ contain un-archived items, unless the item selected is archived it will then appear.
147
+
148
+ eg. A ticket has a priority set to high, later the high selection list item was archived, when we edit the ticket record again the item will show in the list even though it is archived
149
+
150
+ #### Order
151
+
152
+ The list will by default display in alphanumeric order, unless you add position values and then it will display in the values.
153
+
154
+ ## Configuration
155
+
156
+ If you use a class name other than `Selection` as your selection model, you must
157
+ tell selections so by adding the following to a new file, `config/initializers/selections.rb`:
158
+
159
+ ```ruby
160
+ Selections.model { YourSelectionModel }
161
+ ```
162
+
163
+ # TODO
164
+
165
+ * Add model generators
166
+ * Add selections management scaffold/generator
167
+
168
+ ## Contributing
169
+
170
+ 1. Fork it
171
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
172
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
173
+ 4. Push to the branch (`git push origin my-new-feature`)
174
+ 5. Create new Pull Request
175
+
176
+ ## YAML example
177
+
178
+ ```yaml
179
+ priority:
180
+ name: Priorities
181
+ parent:
182
+ position_value:
183
+ system_code: priority
184
+ is_system: false
185
+ priority_high:
186
+ name: High
187
+ parent: priority
188
+ position_value: 30
189
+ system_code: $LABEL
190
+ is_system:
191
+ priority_medium:
192
+ name: Medium
193
+ parent: priority
194
+ position_value: 20
195
+ system_code: $LABEL
196
+ is_system:
197
+ priority_low:
198
+ name: Low
199
+ parent: priority
200
+ position_value: 10
201
+ system_code: $LABEL
202
+ is_system:
203
+ is_default: true
204
+
205
+
206
+ contact_category:
207
+ name: Contact Categories
208
+ parent:
209
+ position_value:
210
+ system_code: contact_category
211
+ is_system: false
212
+ contact_category_junior:
213
+ name: Junior Tech
214
+ parent: contact_category
215
+ position_value:
216
+ system_code: $LABEL
217
+ is_system:
218
+ contact_category_senior:
219
+ name: Senior Tech
220
+ parent: contact_category
221
+ position_value:
222
+ system_code: $LABEL
223
+ is_system:
224
+ contact_category_manager:
225
+ name: Manager
226
+ parent: contact_category
227
+ position_value:
228
+ system_code: $LABEL
229
+ is_system:
230
+ archived_at: <%= Time.now %>
231
+ contact_category_ceo:
232
+ name: CEO
233
+ parent: contact_category
234
+ position_value:
235
+ system_code: $LABEL
236
+ is_system:
237
+ ```
data/Rakefile CHANGED
@@ -1,31 +1,5 @@
1
- #!/usr/bin/env rake
2
- begin
3
- require 'bundler/setup'
4
- rescue LoadError
5
- puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
- end
7
- begin
8
- require 'rdoc/task'
9
- rescue LoadError
10
- require 'rdoc/rdoc'
11
- require 'rake/rdoctask'
12
- RDoc::Task = Rake::RDocTask
13
- end
14
-
15
- RDoc::Task.new(:rdoc) do |rdoc|
16
- rdoc.rdoc_dir = 'rdoc'
17
- rdoc.title = 'Selections'
18
- rdoc.options << '--line-numbers'
19
- rdoc.rdoc_files.include('README.rdoc')
20
- rdoc.rdoc_files.include('lib/**/*.rb')
21
- end
22
-
23
- APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
24
- load 'rails/tasks/engine.rake'
25
-
26
-
27
- Bundler::GemHelper.install_tasks
28
-
1
+ require "bundler/gem_tasks"
29
2
  require 'rspec/core/rake_task'
3
+
30
4
  RSpec::Core::RakeTask.new(:spec)
31
- task :default => :spec
5
+ task default: :spec
@@ -1,7 +1,23 @@
1
- require "rails"
2
- require "selections/engine"
3
- require "acts_as_tree"
4
- require "selections/selection_select"
1
+ require 'selections/version'
2
+ require 'active_record'
3
+ require 'action_view'
5
4
 
6
- #module Selections
7
- #end
5
+ module Selections
6
+
7
+ require 'selections/belongs_to_selection'
8
+ require 'selections/form_builder_extensions'
9
+ require 'selections/selectable'
10
+
11
+ # Given a block, will set how we find / detect the current model
12
+ # used for selections, without a block, will return the value.
13
+ # Note: Needed iff you are using a model other than Selection.
14
+ def self.model(&block)
15
+ if block
16
+ @model = block
17
+ else
18
+ @model ||= lambda { Selection }
19
+ @model.call
20
+ end
21
+ end
22
+
23
+ end
@@ -0,0 +1,20 @@
1
+ module Selections
2
+ module BelongsToSelection
3
+
4
+ # Helper for belongs_to and accepts all the standard rails options
5
+ #
6
+ #Example
7
+ # belongs_to_selection :priority
8
+ #
9
+ # by default adds - class_name: "Selection"
10
+
11
+ def belongs_to_selection(target, options={})
12
+ belongs_to target, options.merge(:class_name => "Selection")
13
+ end
14
+
15
+ ActiveSupport.on_load :active_record do
16
+ extend Selections::BelongsToSelection
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,86 @@
1
+ module Selections
2
+ module FormBuilderExtensions
3
+ # Create a select list based on the field name finding items within Selection.
4
+ #
5
+ #
6
+ # Example
7
+ # form_for(@ticket) do |f|
8
+ # f. select("priority")
9
+ #
10
+ # Uses priority_id from the ticket table and creates options list based on items in Selection table with a system_code of
11
+ # either priority or ticket_priority
12
+ #
13
+ # options = {} and html_options = {} suport all the keys as the rails library select_tag does.
14
+ #
15
+ # options
16
+ # * +system_code+ - Overrides the automatic system_code name based on the fieldname and looks up the list of items in Selection
17
+
18
+ def selections(field, options = {}, html_options = {})
19
+ SelectionTag.new(self, object, field, html_options, options).to_tag
20
+ end
21
+
22
+ class SelectionTag #:nodoc:
23
+ attr_reader :form, :object, :field, :html_options, :options, :selection, :field_id, :system_code_name
24
+
25
+ def initialize(form, object, field, html_options, options)
26
+ @form = form
27
+ @object = object
28
+ @field = field
29
+ @html_options = html_options || {}
30
+
31
+ @system_code_name = options[:system_code] || field
32
+ @selection = Selections.model
33
+ @field_id ||= (field.to_s + "_id").to_sym
34
+ @options = options || {}
35
+ end
36
+
37
+ def include_blank?
38
+ if options[:include_blank].nil?
39
+ !!((object.try(:new_record?) || !object.send(field_id))) && default_item.blank?
40
+ else
41
+ !!options[:include_blank]
42
+ end
43
+ end
44
+
45
+ def system_code
46
+ @system_code ||= selection.where(system_code: system_code_name.to_s).first
47
+ @system_code ||= selection.where(system_code: "#{form.object_name}_#{system_code_name}").first
48
+ end
49
+
50
+ def items
51
+ @items ||= system_code.children.filter_archived_except_selected(object.send(field_id))
52
+ end
53
+
54
+ def to_tag
55
+ if system_code
56
+ #TODO add default style
57
+ #html_options[:style] ||=
58
+ options[:include_blank] = include_blank?
59
+ options[:selected] = selected_item
60
+ form.select field_id, items.map { |item| [item.name, item.id] }, options, html_options
61
+ else
62
+ "Invalid system_code of '#{system_code_name}'"
63
+ end
64
+ end
65
+
66
+ def selected_item
67
+ if object.new_record?
68
+ default_item
69
+ else
70
+ object.send(field_id).to_s
71
+ end
72
+ end
73
+
74
+ def default_item
75
+ items.where(:is_default => true).first.try(:id).to_s
76
+ end
77
+ end
78
+
79
+ ActiveSupport.on_load :action_view do
80
+ ActionView::Helpers::FormBuilder.class_eval do
81
+ include Selections::FormBuilderExtensions
82
+ end
83
+ end
84
+
85
+ end
86
+ end