rails_stuff 0.1.0

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 (42) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +24 -0
  5. data/.travis.yml +8 -0
  6. data/Gemfile +21 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +350 -0
  9. data/Rakefile +22 -0
  10. data/bin/console +7 -0
  11. data/bin/git-hooks/pre-commit +14 -0
  12. data/bin/install_git_hooks +8 -0
  13. data/bin/setup +8 -0
  14. data/lib/net/http/debug.rb +26 -0
  15. data/lib/rails_stuff/helpers/all.rb +12 -0
  16. data/lib/rails_stuff/helpers/bootstrap.rb +34 -0
  17. data/lib/rails_stuff/helpers/forms.rb +21 -0
  18. data/lib/rails_stuff/helpers/links.rb +38 -0
  19. data/lib/rails_stuff/helpers/resource_form.rb +49 -0
  20. data/lib/rails_stuff/helpers/text.rb +28 -0
  21. data/lib/rails_stuff/helpers/translation.rb +29 -0
  22. data/lib/rails_stuff/helpers.rb +14 -0
  23. data/lib/rails_stuff/nullify_blank_attrs.rb +23 -0
  24. data/lib/rails_stuff/params_parser.rb +121 -0
  25. data/lib/rails_stuff/railtie.rb +54 -0
  26. data/lib/rails_stuff/random_uniq_attr.rb +48 -0
  27. data/lib/rails_stuff/redis_storage.rb +119 -0
  28. data/lib/rails_stuff/resources_controller/actions.rb +31 -0
  29. data/lib/rails_stuff/resources_controller/basic_helpers.rb +161 -0
  30. data/lib/rails_stuff/resources_controller/resource_helper.rb +31 -0
  31. data/lib/rails_stuff/resources_controller/responder.rb +21 -0
  32. data/lib/rails_stuff/resources_controller/sti_helpers.rb +62 -0
  33. data/lib/rails_stuff/resources_controller.rb +42 -0
  34. data/lib/rails_stuff/sort_scope.rb +71 -0
  35. data/lib/rails_stuff/statusable.rb +130 -0
  36. data/lib/rails_stuff/test_helpers/rails.rb +6 -0
  37. data/lib/rails_stuff/test_helpers/response.rb +34 -0
  38. data/lib/rails_stuff/types_tracker.rb +50 -0
  39. data/lib/rails_stuff/version.rb +14 -0
  40. data/lib/rails_stuff.rb +19 -0
  41. data/rails_stuff.gemspec +25 -0
  42. metadata +126 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 82159ba1a8b42ef1cea7d901d966408ae47dc832
4
+ data.tar.gz: c4d212a0f28c39142139945488c73c7c5eb10eb4
5
+ SHA512:
6
+ metadata.gz: 767e814c2d06cc0ec03988d0a5a510edeba5407310a3d72c1592ff6e947fb4ee58adba0ad0efa6ee2d0e33a8fbd0d58c5a250a900d2fd5bbb766c7b067028443
7
+ data.tar.gz: 49ce30b733a8a28ab71dcb6a7cafd496f74f391000f52ae9597be8605810564b781bfc838dff3f92ad8f60d922d6f8ecbf00a99d77390c929caf1a8d4bae3f60
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,24 @@
1
+ AllCops:
2
+ RunRailsCops: true
3
+
4
+ Style/AlignParameters:
5
+ # Disable, till rubocop supports combination of styles.
6
+ # Use one of this styles where appropriate, keep it clean, compact and readable.
7
+ Enabled: false
8
+ EnforcedStyle:
9
+ - aligned
10
+ - with_fixed_indentation
11
+ Style/ClosingParenthesisIndentation: {Enabled: false}
12
+ Style/Documentation: {Enabled: false}
13
+ Style/DotPosition: {EnforcedStyle: trailing}
14
+ Style/IfUnlessModifier: {Enabled: false}
15
+ Style/ModuleFunction: {Enabled: false}
16
+ Style/MultilineOperationIndentation: {EnforcedStyle: indented}
17
+ Style/PredicateName: {Enabled: false}
18
+ Style/SignalException: {EnforcedStyle: only_raise}
19
+ Style/SpaceInsideHashLiteralBraces: {EnforcedStyle: no_space}
20
+ Style/TrailingComma: {Enabled: false}
21
+
22
+ Metrics/AbcSize: {Max: 19}
23
+ Metrics/LineLength: {Max: 100}
24
+ Metrics/MethodLength: {Max: 30}
data/.travis.yml ADDED
@@ -0,0 +1,8 @@
1
+ language: ruby
2
+ cache: bundler
3
+ rvm:
4
+ - 2.2.3
5
+ services:
6
+ - redis
7
+ notifications:
8
+ email: false
data/Gemfile ADDED
@@ -0,0 +1,21 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
3
+
4
+ group :development do
5
+ gem 'sdoc', '~> 0.4.1'
6
+ gem 'pry', '~> 0.10.1'
7
+
8
+ gem 'sqlite3', '~> 1.3.10'
9
+ gem 'database_cleaner', '~> 1.5.0'
10
+ gem 'pooled_redis', '~> 0.2.1'
11
+ gem 'activemodel_translation', '~> 0.1.0'
12
+ gem 'has_scope', '~> 0.6.0'
13
+ gem 'responders', '~> 2.1.0'
14
+ gem 'kaminari', '~> 0.16.3'
15
+
16
+ gem 'rspec', '~> 3.3.0'
17
+ gem 'rspec-its', '~> 1.1.0'
18
+ gem 'rspec-rails', '~> 3.3.3'
19
+
20
+ gem 'rubocop', '~> 0.33.0'
21
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Max Melentiev
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,350 @@
1
+ # RailsStuff
2
+ [![Gem Version](https://badge.fury.io/rb/rails_stuff.svg)](http://badge.fury.io/rb/rails_stuff)
3
+ [![Code Climate](https://codeclimate.com/github/printercu/rails_stuff/badges/gpa.svg)](https://codeclimate.com/github/printercu/rails_stuff)
4
+ [![Build Status](https://travis-ci.org/printercu/rails_stuff.svg)](https://travis-ci.org/printercu/rails_stuff)
5
+
6
+ Collection of useful modules for Rails.
7
+
8
+ #### Controllers:
9
+
10
+ - __[ResourcesController](#resourcescontroller)__
11
+ DRY! Keep your controllers clean.
12
+ - __[SortScope](#sortscope)__
13
+ Helper for `has_scope` to sort collections safely.
14
+
15
+ #### Models:
16
+
17
+ - __[NullifyBlankAttrs](#nullifyblankattrs)__
18
+ Proxies writers to replace empty values with `nil`.
19
+ - __[RandomUniqAttr](#randomuniqattr)__
20
+ You generate random values for attributes, it'll ensure they are uniq.
21
+ - __[Statusable](#statusable)__
22
+ `ActiveRecord::Enum` with more features.
23
+ - __[TypesTracker](#typestracker)__
24
+ Advanced descendants tracker.
25
+
26
+ #### Misc:
27
+
28
+ - __[ParamsParser](#paramsparser)__
29
+ Type-cast params outside of `ActiveRecord`.
30
+ - __[RedisStorage](#redisstorage)__
31
+ Simple way to store collections in key-value storage. With scoping and
32
+ key generation.
33
+
34
+ #### Helpers:
35
+
36
+ - __TranslationHelper__
37
+ `translate_action`, `translate_confirmation` helpers to translate
38
+ action names and confirmations in the same way all over you app.
39
+ - __LinksHelper__
40
+ Keep your links for basic actions consistent.
41
+ - __Bootstrap__
42
+ For bootstrap-formatted flash messages.
43
+ - __Forms__
44
+ `hidden_params_fields` to bypass query params in GET-forms.
45
+
46
+ __[Helpers usage](#helpers)__
47
+
48
+ ## Installation
49
+
50
+ Add this line to your application's Gemfile:
51
+
52
+ ```ruby
53
+ gem 'rails_stuff'
54
+ ```
55
+
56
+ And then execute:
57
+
58
+ $ bundle
59
+
60
+ Or install it yourself as:
61
+
62
+ $ gem install rails_stuff
63
+
64
+ ## Usage
65
+
66
+ All modules are lazy loaded, so it's ok to require whole gem at once.
67
+ There is railtie which will include some of modules into `ActiveRecord::Base`
68
+ and `ActionController::Base` by default. You can disable this behavior in
69
+ initializer:
70
+
71
+ ```ruby
72
+ # Disable auto-setup:
73
+ RailsStuff.load_modules = []
74
+
75
+ # Enable particular modules:
76
+ RailsStuff.load_modules = %i(sort_scope statusable)
77
+ ```
78
+
79
+ You can override base classes for controller/model with `.base_controller=`,
80
+ `.base_model=`.
81
+
82
+ Works only with ruby 2.0+, tested with Rails 4.2.
83
+
84
+ There can be lack of documentation in README. Please navigate to module and
85
+ check docs & code (press `t` on github) if you miss something.
86
+
87
+ ### ResourcesController
88
+
89
+ Similar to [InheriteResource](https://github.com/josevalim/inherited_resources)
90
+ but much simpler. It adds implementations for basic actions and
91
+ accessors for collection and resource. There is no options for almost everything,
92
+ but it's easy to extend.
93
+
94
+ It's main purpose is to ged rid of `@user ||= User.find params[:id]`, and keep
95
+ controllers clean:
96
+
97
+ ```ruby
98
+ class ApplicationController < ActionController::Base
99
+ extend RailsStuff::ResourcesController # when using without railtie
100
+ end
101
+
102
+ class UsersController < ApplicationController
103
+ resources_controller
104
+ permit_attrs :name, :email
105
+ end
106
+
107
+ class ProjectsController < ApplicationController
108
+ resources_controller sti: true,
109
+ after_save_action: :index,
110
+ source_relation: -> { user.projects }
111
+ resource_helper :user
112
+ permit_attrs :name
113
+ permit_attrs_for Project::External, :company
114
+ permit_attrs_for Project::Internal, :department
115
+ end
116
+ ```
117
+
118
+ There is built-in support for pagination with Kaminari.
119
+ It's enabled automatically if `kaminari` gem is loaded.
120
+
121
+ Currently depends on `gem 'responders', '> 2.0'`.
122
+
123
+ ### SortScope
124
+
125
+ ```ruby
126
+ # in controller
127
+ extend RailsStuff::SortScope # when using without railtie
128
+
129
+ sort_scope by: [:name, :created_at, :balance], default: [:name]
130
+
131
+ # this scope will accept
132
+ # - `sort=name`
133
+ # - `sort=name&sort_desc=true`
134
+ # - `sort[name]&sort[created_at]`
135
+ # - `sort[name]&sort[created_at]=desc
136
+ ```
137
+
138
+ Requires `gem 'has_scope'`.
139
+
140
+ ### NullifyBlankAttrs
141
+
142
+ Defines proxies for writers to replace empty values with `nil`.
143
+
144
+ ```ruby
145
+ # in model
146
+ extend RailsStuff::NullifyBlankAttrs # when using without railtie
147
+
148
+ nullify_blank_attrs :email, :title
149
+ ```
150
+
151
+ ### RandomUniqAttr
152
+
153
+ Uses database's UNIQUE constraints and transactions to generate uniq random values.
154
+ You need to make field nullable and add unique index on it.
155
+ The way it works:
156
+
157
+ - Instance is saved as usual
158
+ - If random fields are not empty, it does nothing
159
+ - Generates random value and tries to update instance
160
+ - If `RecordNotUnique` is occurred, it keeps trying to generate new values.
161
+
162
+ ```ruby
163
+ # in model
164
+ extend RailsStuff::RandomUniqAttr # when using without railtie
165
+
166
+ # Uses DEFAULT_GENERATOR which is SecureRandom(32)
167
+ random_uniq_attr :token
168
+
169
+ # Uses custom generator, which takes template from settings
170
+ random_uniq_attr(:code) do |instance|
171
+ MyGenerator.generate(instance.parent.code_template)
172
+ end
173
+ ```
174
+
175
+ ### Statusable
176
+
177
+ ```ruby
178
+ class User < ActiveRecord::Base
179
+ extend RailsStuff::RandomUniqAttr # when using without railtie
180
+
181
+ STATUSES = %i(confirmed banned)
182
+ has_status_field # uses #status field and STATUSES as values
183
+
184
+ # Or pass everything explicitly
185
+ has_status_field :subscription_status, %i(expired active), prefix: :subs_
186
+ # :prefix is used for methods that are build
187
+ end
188
+
189
+ user = User.first
190
+
191
+ # And you get:
192
+ # Scopes
193
+ User.confirmed.subs_active
194
+ User.not_banned.not_subs_expired
195
+ # Useful with has_scope
196
+ User.with_status(param[:status]).with_subscription_status(params[:subs_status])
197
+
198
+ # Translation & select helpers (requires activemodel_translation gem)
199
+ User.status_name(:active)
200
+ user.subscription_status_name # translates current status
201
+ User.status_select_options
202
+ User.subscription_status_select_options except: [:expired]
203
+
204
+ # Accessors
205
+ user.status = 'confirmed' or user.confirmed!
206
+ user.status_sym # :confirmed
207
+ user.subscription_status = :active or user.subs_active!
208
+ user.subscription_status # 'active'
209
+ user.banned? or user.subs_expired?
210
+
211
+ # ... and inclusion validator
212
+ ```
213
+
214
+ ### TypesTracker
215
+
216
+ ```ruby
217
+ class Project
218
+ extend RailsStuff::TypesTracker
219
+ # you can also override default list class (Array) with:
220
+ self.types_list_class = FilterableArray
221
+ # smth ...
222
+
223
+ # If you want to show all available descendants in development
224
+ # (ex. in dropdown/select), you definitely want this:
225
+ eager_load_types! # will load all files in app/models/project
226
+ # or pass folder explicitly:
227
+ eager_load_types!('lib/path/to/projects')
228
+ end
229
+
230
+ class Project::Big < Project
231
+ unregister_type # remove this class from types_list
232
+
233
+ # Or add options for custom list.
234
+ # Following will call types_list.add Project::Big, :arg, option: :example
235
+ register_type :arg, option: :example
236
+ end
237
+
238
+ class Project::Internal < Project::Big; end
239
+ class Project::External < Project::Big; end
240
+ class Project::Small < Project; end
241
+
242
+ Project.types_list # [Internal, External, Small]
243
+ ```
244
+
245
+ ### ParamsParser
246
+
247
+ Have you missed type-casting outside of `ActiveRecord::Base`? Here is it:
248
+
249
+ ```ruby
250
+ ParamsParser.parse_int(params[:field]) # _float, _string, _boolean, _datetime
251
+ ParamsParser.parse_int_array(params[:field_with_array])
252
+ ParamsParser.parse_json(json_string)
253
+
254
+ # There is basic .parse method. It runs block only if input is not nil
255
+ # and reraises all errors with ParamsParser::Error
256
+ ParamsParser.parse(input) { |x| this_can_raise_exception(x) }
257
+
258
+ # So you can handle all errors in controller with
259
+ rescue_from ParamsParser::Error, with: -> { head :bad_request }
260
+ ```
261
+
262
+ ### RedisStorage
263
+
264
+ Simple module to organize data in key-value store. Uses `ConnectionPool`
265
+ and works good in multi-threaded environments.
266
+ Best used with [PooledRedis](https://github.com/printercu/pooled_redis).
267
+
268
+ ```ruby
269
+ class Model
270
+ extend RailsStuff::SedisStorage
271
+
272
+ self.redis_prefix = :other_prefix # default to underscored model name
273
+
274
+ # override .dump, .load for custom serialization. Default to Marshal
275
+
276
+ # It uses Rails.redis_pool by default. Override it with
277
+ self.redis_pool = ConnectionPool.new { Redis.new(my_options) }
278
+ end
279
+
280
+ Model.get('key') # GET other_prefix:key
281
+ Model.get(['composite', 'key']) # GET other_prefix:composite:key
282
+ # .delete works the same way
283
+
284
+ Model.set('key', data) or Model.set(['composite', 'key'], data)
285
+ next_id = Model.set(nil, data) # auto-incremented per-model id
286
+ next_id = Model.set(['composite', nil], data) # auto-incremented per-scope id
287
+ Model.set(id, data, ex: 10) # pass options for redis
288
+ # Or set per-model options for all .set requests:
289
+ Model.redis_set_options = {ex: 10}
290
+
291
+ # generate ids:
292
+ Model.next_id or Model.next_id(['composite', 'scope'])
293
+ Model.reset_id_seq or Model.reset_id_seq(['composite', 'scope'])
294
+ ```
295
+
296
+ ### Helpers
297
+
298
+ Include helper module into `ApplicationHelper`.
299
+ Or use `RailsStuff::Helpers::All` to include all helpers together.
300
+
301
+ Add this sections to your translations ymls:
302
+
303
+ ```yml
304
+ helpers:
305
+ actions:
306
+ edit: Change
307
+ delete: Forget about it
308
+ confirm: Really?
309
+ confirmations:
310
+ delete: Will you miss it?
311
+ ```
312
+
313
+ And use helpers:
314
+
315
+ ```ruby
316
+ translate_action(:edit) or translate_action(:delete)
317
+ link_to 'x', url_for(resource),
318
+ method: :delete, data: {confirm: translate_confirmation(:delete)}
319
+ translate_confirmation(:purge_all) # Fallback to default: 'Really?'
320
+
321
+ # There are helpers for basic links, take a look on helpers/links.rb to know
322
+ # how to tune it:
323
+ link_to_edit or link_to_edit('url') or link_to_edit([:scope, resource])
324
+ link_to_destroy or link_to_destroy('url') or link_to_destroy([:scope, resource])
325
+ ```
326
+
327
+ Translation helpers are cached, so there is no need to cache it by yourself in
328
+ template if you want to decrease computations. And be aware of it if you
329
+ switch locales while rendering single view.
330
+
331
+ ## Development
332
+
333
+ After checking out the repo, run `bin/setup` to install dependencies.
334
+ Then, run `bin/console` for an interactive prompt that will allow you to experiment.
335
+
336
+ To install this gem onto your local machine, run `bundle exec rake install`.
337
+ To release a new version, update the version number in `version.rb`,
338
+ and then run `bundle exec rake release` to create a git tag for the version,
339
+ push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
340
+
341
+ ## Contributing
342
+
343
+ 1. Fork it ( https://github.com/printercu/rails_stuff/fork )
344
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
345
+ 3. Implement your feature:
346
+ - Write failing spec for your feature
347
+ - Write code
348
+ - Commit your changes (`git commit -am 'Add some feature'`)
349
+ 4. Push to the branch (`git push origin my-new-feature`)
350
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,22 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
7
+
8
+ require 'sdoc'
9
+ RDoc::Task.new(:doc) do |rdoc|
10
+ rdoc.rdoc_dir = 'doc'
11
+
12
+ rdoc.title = 'RailsStuff'
13
+
14
+ rdoc.options << '--markup' << 'markdown'
15
+ rdoc.options << '-e' << 'UTF-8'
16
+ rdoc.options << '--format' << 'sdoc'
17
+ rdoc.options << '--template' << 'rails'
18
+ rdoc.options << '--all'
19
+
20
+ rdoc.rdoc_files.include('README.md')
21
+ rdoc.rdoc_files.include('lib/**/*.rb')
22
+ end
data/bin/console ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'rails_stuff'
5
+
6
+ require 'pry'
7
+ Pry.start
@@ -0,0 +1,14 @@
1
+ #!/bin/bash
2
+
3
+ pattern=$(echo -n '\.rb
4
+ \.gemspec
5
+ \.jbuilder
6
+ \.rake
7
+ config\.ru
8
+ Gemfile
9
+ Rakefile' | tr "\\n" '|')
10
+
11
+ files=`git diff --cached --name-status | grep -E "^[AM].*($pattern)$" | cut -f2-`
12
+ if [ -n "$files" ]; then
13
+ bundle exec rubocop $files --force-exclusion
14
+ fi
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ root = File.expand_path('../../', __FILE__)
4
+ hooks_dir = "#{root}/bin/git-hooks"
5
+
6
+ `ls -1 #{hooks_dir}`.each_line.map(&:strip).each do |file|
7
+ `ln -sf #{hooks_dir}/#{file} #{root}/.git/hooks/#{file}`
8
+ end
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+ bin/install_git_hooks
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,26 @@
1
+ require 'net/http'
2
+
3
+ class << Net::HTTP
4
+ # Redefines `.new` to set debug device for all new instances.
5
+ def debug!(out = $stderr)
6
+ return if respond_to?(:__new__)
7
+ class << self
8
+ alias_method :__new__, :new
9
+ end
10
+
11
+ define_singleton_method :new do |*args, &blk|
12
+ instance = __new__(*args, &blk)
13
+ instance.set_debug_output(out)
14
+ instance
15
+ end
16
+ end
17
+
18
+ # Restores original `.new`.
19
+ def disable_debug!
20
+ return unless respond_to?(:__new__)
21
+ class << self
22
+ alias_method :new, :__new__
23
+ remove_method :__new__
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,12 @@
1
+ module RailsStuff
2
+ module Helpers
3
+ # Collection of all helper modules.
4
+ module All
5
+ include Translation
6
+ include Links
7
+ include Bootstrap
8
+ include Text
9
+ include Forms
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,34 @@
1
+ require 'active_support/core_ext/hash/keys'
2
+ require 'active_support/core_ext/hash/transform_values'
3
+
4
+ module RailsStuff
5
+ module Helpers
6
+ module Bootstrap
7
+ BOOTSTRAP_FLASH_TYPE = {
8
+ success: 'alert-success',
9
+ error: 'alert-danger',
10
+ alert: 'alert-warning',
11
+ notice: 'alert-info',
12
+ }.stringify_keys.freeze
13
+
14
+ def flash_messages
15
+ flash.map do |type, message|
16
+ content_tag :div, class: [:alert, BOOTSTRAP_FLASH_TYPE[type] || type] do
17
+ content_tag(:button, '&times;'.html_safe, class: :close, data: {dismiss: :alert}) +
18
+ simple_format(message)
19
+ end
20
+ end.join.html_safe
21
+ end
22
+
23
+ ICONS = {
24
+ destroy: %(<span class='glyphicon icon-destroy'></span>),
25
+ edit: %(<span class='glyphicon icon-edit'></span>),
26
+ new: %(<span class='glyphicon icon-add'></span>),
27
+ }.tap { |x| x.transform_values!(&:html_safe) if ''.respond_to?(:html_safe) }
28
+
29
+ def basic_link_icons
30
+ ICONS
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,21 @@
1
+ module RailsStuff
2
+ module Helpers
3
+ module Forms
4
+ # Returns hidden field tags for requested fields when they are present in params.
5
+ # Usually used to bypass params in GET-forms.
6
+ def hidden_params_fields(*fields)
7
+ inputs = fields.flat_map do |field|
8
+ next unless params.key?(field)
9
+ val = params[field]
10
+ if val.is_a?(Array)
11
+ name = "#{field}[]"
12
+ val.map { |str| [name, str] }
13
+ else
14
+ [[field, val]]
15
+ end
16
+ end
17
+ safe_join inputs.map { |(name, val)| hidden_field_tag name, val if name }
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,38 @@
1
+ module RailsStuff
2
+ module Helpers
3
+ # Link helpers for basic actions.
4
+ module Links
5
+ ICONS = {
6
+ destroy: -> { translate_action(:destroy) },
7
+ edit: -> { translate_action(:edit) },
8
+ new: -> { translate_action(:new) },
9
+ }
10
+
11
+ def basic_link_icons
12
+ ICONS
13
+ end
14
+
15
+ def basic_link_icon(action)
16
+ val = basic_link_icons[action]
17
+ val.is_a?(Proc) ? instance_exec(&val) : val
18
+ end
19
+
20
+ def link_to_destroy(url, **options)
21
+ link_to basic_link_icon(:destroy), url, {
22
+ title: translate_action(:delete),
23
+ method: :delete,
24
+ data: {confirm: translate_confirmation(:delete)},
25
+ }.merge!(options)
26
+ end
27
+
28
+ def link_to_edit(url = nil, **options)
29
+ link_to basic_link_icon(:edit), (url || url_for(action: :edit)),
30
+ {title: translate_action(:edit)}.merge!(options)
31
+ end
32
+
33
+ def link_to_new(url = nil, **options)
34
+ link_to basic_link_icon(:new), (url || url_for(action: :new)), options
35
+ end
36
+ end
37
+ end
38
+ end