ransack_abbreviator 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.md CHANGED
@@ -8,4 +8,9 @@
8
8
 
9
9
  ## v0.0.6
10
10
 
11
- * First stable release
11
+ * First stable release
12
+
13
+ ## v0.0.7
14
+
15
+ * Added ability to reference abbreviations in a form by adding a 'abbr_' prefix on each form element.
16
+ * Created an 'abbr_attribute_select' form helper that does the same as Ransack's attribute_select, but with abbreviations.
data/README.md CHANGED
@@ -16,7 +16,7 @@ gem 'ransack_abbreviator'
16
16
  The abbreviator should cause absolutely no problems if you decide to not use abbreviations. It only kicks in when an abbreviation is detected in the params. That said, here's how to use it:
17
17
 
18
18
  #### Define Abbreviations
19
- First, define some abbreviations for columns and associations that can be queried in your search form. You can create a ransack_abbreviator.yml file in your config directory in a structure like this:
19
+ First, define some abbreviations for columns and associations. One way to do that is to create a ransack_abbreviator.yml file in your config directory in a structure like this:
20
20
 
21
21
  ransack_abbreviations:
22
22
  columns:
@@ -36,27 +36,30 @@ RansackAbbreviator.configure do |config|
36
36
  end
37
37
  ```
38
38
  #### Use the Abbreviated Attribute in your Form
39
- In your form, pass the Ransack language you would normally use (along with the search object) to a helper called ransack_abbreviation_for:
39
+ In your form, simply add an 'abbr_' prefix to each form element:
40
40
 
41
41
  <%= search_form_for @q do |f| %>
42
- <%= f.text_field ransack_abbreviation_for(@q, :name_cont) %>
43
- <%= f.text_field ransack_abbreviation_for(@q, :articles_title_start) %>
42
+ <%= f.abbr_label :name_cont, "Name Contains" %>
43
+ <%= f.abbr_text_field :name_cont %>
44
+ <%= f.abbr_label :articles_title_start, "Title of article starts with" %>
45
+ <%= f.abbr_text_field :articles_title_start %>
44
46
  <%= f.submit %>
45
47
  <% end %>
46
48
 
47
- When the above form is submitted, what would have normally been a URL param of 'name_cont' is now 'nm_cont'. 'articles_title_start' is now 'ars.tl_start'.
49
+ When the above form is submitted, what would have normally been a URL param of 'name_cont' is now 'nm_cont'. 'articles_title_start' is now 'ars.tl_start'. View the source of the generated form to see for yourself!
48
50
 
49
- See the [Ransack](https://github.com/ernie/ransack) documentation on how to reference associations, columns, and predicates.
51
+ If you're using Ransack's 'attribute_select', simply change it to 'abbr_attribute_select' to utilize abbreviations over the full attribute name.
52
+
53
+ See the [Ransack](https://github.com/ernie/ransack) documentation for more info on the language Ransack uses and how to reference associations, columns, and predicates.
50
54
 
51
55
  #### Remove those POST hacks!
52
56
  Hopefully, the URL is now at least half the size it could have been before and you can remove all the POST hacks you did to get pagination and whatnot to work correctly!
53
57
 
54
58
  ### Some Notes
55
- * ransack_abbreviation_for abbreviates what it can, and returns the full name for what it cannot. For example, if you forgot to abbreviate 'articles', then ransack_abbreviation_for(@q, :articles_title_start) would return 'articles.tl_start'
59
+ * The code works by abbreviating what it can and leaving what it cannot alone. For example, if you forgot to abbreviate 'articles', then <%= f.abbr_text_field :articles_title_start %> would return 'articles.tl_start' as the ID and param of the text field.
56
60
 
57
61
  ### To Do
58
62
  * Support abbreviation of 'ransacker' attributes
59
- * Extend the 'attribute_select' form helper to support returning attributes as their abbreviations
60
63
 
61
64
  ### License and Copyright
62
65
  MIT License. Copyright &copy; 2013 [Jamie Davidson](http://jamie-davidson.com)
@@ -23,4 +23,5 @@ require "ransack_abbreviator/ransack_extensions/nodes/condition"
23
23
  require "ransack_abbreviator/ransack_extensions/context"
24
24
  require "ransack_abbreviator/ransack_extensions/search"
25
25
  require 'ransack_abbreviator/adapters/active_record'
26
- require "ransack_abbreviator/view_helpers"
26
+ require "ransack_abbreviator/view_helpers"
27
+ require "ransack_abbreviator/ransack_extensions/helpers/form_builder"
@@ -14,8 +14,12 @@ module RansackAbbreviator
14
14
  end
15
15
 
16
16
  def ransack_abbreviate_column!(column_name, column_abbr)
17
- raise ActiveModel::MissingAttributeError, "missing attribute: #{column_name}" unless column_names.include?(column_name)
18
- raise "column #{self.ransackable_column_abbreviations.key(column_abbr)} has abbreviaiton #{column_abbr}" if self.ransackable_column_abbreviations.has_value?(column_abbr)
17
+ unless column_names.include?(column_name)
18
+ raise ActiveModel::MissingAttributeError, "missing attribute: #{column_name}"
19
+ end
20
+ if self.ransackable_column_abbreviations.has_value?(column_abbr)
21
+ raise "Column #{self.ransackable_column_abbreviations.key(column_abbr)} already has abbreviaiton #{column_abbr}. Column abbreviations need to be unique"
22
+ end
19
23
  self._ransack_column_abbreviations[column_name] = column_abbr
20
24
  end
21
25
 
@@ -24,19 +28,33 @@ module RansackAbbreviator
24
28
  end
25
29
 
26
30
  def ransack_abbreviate_assoc!(assoc_name, assoc_abbr)
27
- raise ActiveModel::MissingAttributeError, "missing association: #{assoc_name}" unless reflect_on_all_associations.map{|a| a.name.to_s}.include?(assoc_name)
28
- raise "association #{self.ransackable_assoc_abbreviations.key(assoc_abbr)} has abbreviaiton #{assoc_abbr}" if self.ransackable_assoc_abbreviations.has_value?(assoc_abbr)
31
+ unless reflect_on_all_associations.map{|a| a.name.to_s}.include?(assoc_name)
32
+ raise ActiveModel::MissingAttributeError, "missing association: #{assoc_name}"
33
+ end
34
+ if self.ransackable_assoc_abbreviations.has_value?(assoc_abbr)
35
+ raise "Association #{self.ransackable_assoc_abbreviations.key(assoc_abbr)} already has abbreviaiton #{assoc_abbr} Association abbreviations need to be unique"
36
+ end
29
37
  self._ransack_assoc_abbreviations[assoc_name] = assoc_abbr
30
38
  end
31
39
 
32
40
  def ransackable_column_abbreviations
33
- self._ransack_column_abbreviations ||= RansackAbbreviator.column_abbreviations.select{ |key, val| column_names.include?(key) }
41
+ self._ransack_column_abbreviations ||= begin
42
+ self._ransack_column_abbreviations = {}
43
+ RansackAbbreviator.column_abbreviations.select{ |key, val| column_names.include?(key) }.each do |col, abbr|
44
+ raise "Column #{self._ransack_column_abbreviations.key(abbr)} already has abbreviaiton #{abbr}" if self._ransack_column_abbreviations.has_value?(abbr)
45
+ self._ransack_column_abbreviations[col] = abbr
46
+ end
47
+ end
34
48
  end
35
49
 
36
50
  def ransackable_assoc_abbreviations
37
51
  self._ransack_assoc_abbreviations ||= begin
52
+ self._ransack_assoc_abbreviations = {}
38
53
  associations = reflect_on_all_associations.map{|a| a.name.to_s}
39
- RansackAbbreviator.assoc_abbreviations.select{ |key, val| associations.include?(key) }
54
+ RansackAbbreviator.assoc_abbreviations.select{ |key, val| associations.include?(key) }.each do |assoc, abbr|
55
+ raise "Association #{self._ransack_assoc_abbreviations.key(abbr)} already has abbreviaiton #{abbr}" if self._ransack_assoc_abbreviations.has_value?(abbr)
56
+ self._ransack_assoc_abbreviations[assoc] = abbr
57
+ end
40
58
  end
41
59
  end
42
60
 
@@ -11,8 +11,9 @@ module RansackAbbreviator
11
11
 
12
12
  def column_abbreviations=(abbreviations)
13
13
  if abbreviations
14
+ raise ArgumentError, "abbreviates must be a Hash" unless abbreviations.is_a?(Hash)
14
15
  if !(abbreviations.values & RansackAbbreviator::Constants::RESERVED_KEYWORDS).blank?
15
- fail "You used a reserved keyword as a column abbreviation. Reserverd keywords: #{RansackAbbreviator::Constants::RESERVED_KEYWORDS.join(", ")}"
16
+ raise ArgumentError, "You used a reserved keyword as a column abbreviation. Reserverd keywords: #{RansackAbbreviator::Constants::RESERVED_KEYWORDS.join(", ")}"
16
17
  end
17
18
 
18
19
  @@column_abbreviations = abbreviations
@@ -21,8 +22,9 @@ module RansackAbbreviator
21
22
 
22
23
  def assoc_abbreviations=(abbreviations)
23
24
  if abbreviations
25
+ raise ArgumentError, "abbreviates must be a Hash" unless abbreviations.is_a?(Hash)
24
26
  if !(abbreviations.values & RansackAbbreviator::Constants::RESERVED_KEYWORDS).blank?
25
- fail "You used a reserved keyword as an association abbreviation. Reserverd keywords: #{RansackAbbreviator::Constants::RESERVED_KEYWORDS.join(", ")}"
27
+ raise ArgumentError, "You used a reserved keyword as an association abbreviation. Reserverd keywords: #{RansackAbbreviator::Constants::RESERVED_KEYWORDS.join(", ")}"
26
28
  end
27
29
 
28
30
  @@assoc_abbreviations = abbreviations
@@ -0,0 +1,65 @@
1
+ require 'action_view'
2
+
3
+ module Ransack
4
+ module Helpers
5
+ class FormBuilder < ::ActionView::Helpers::FormBuilder
6
+ def method_missing(method_id, *args, &block)
7
+ method_name = method_id.to_s
8
+ if method_name.starts_with?('abbr_')
9
+ raise ArgumentError, "abbreviated form helpers must be called inside a search FormBuilder!" unless object.respond_to?(:context)
10
+ ransack_name = args.shift
11
+ actual_method = method_name.sub('abbr_', '')
12
+ abbreviated_ransack_name = object.context.encode_parameter(ransack_name)
13
+ self.send(actual_method, abbreviated_ransack_name, *args, &block)
14
+ else
15
+ super
16
+ end
17
+ end
18
+
19
+ def abbr_attribute_select(options = {}, html_options = {})
20
+ raise ArgumentError, "abbr_attribute_select must be called inside a search FormBuilder!" unless object.respond_to?(:context)
21
+ options[:include_blank] = true unless options.has_key?(:include_blank)
22
+ associations = association_array(options[:associations])
23
+ if associations.size > 0
24
+ bases = [''] + associations
25
+ grouped_collection = encoded_attribute_collection_for_bases(bases)
26
+ @template.grouped_collection_select(
27
+ @object_name, :name, grouped_collection, :last, :first, :first, :last,
28
+ objectify_options(options), @default_options.merge(html_options)
29
+ )
30
+ else
31
+ collection = encoded_attribute_collection_for_base
32
+ @template.collection_select(
33
+ @object_name, :name, collection, :first, :last,
34
+ objectify_options(options), @default_options.merge(html_options)
35
+ )
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ def encoded_attribute_collection_for_base(base=nil)
42
+ prefix = base.blank? ? "" : "#{base}_"
43
+ object.context.searchable_attributes(base).map do |attr|
44
+ [
45
+ object.context.encode_parameter(prefix + attr),
46
+ Translate.attribute(prefix + attr, :context => object.context)
47
+ ]
48
+ end
49
+ end
50
+
51
+ def encoded_attribute_collection_for_bases(bases)
52
+ bases.map do |base|
53
+ begin
54
+ [
55
+ Translate.association(base, :context => object.context),
56
+ encoded_attribute_collection_for_base(base)
57
+ ]
58
+ rescue UntraversableAssociationError => e
59
+ nil
60
+ end
61
+ end.compact
62
+ end
63
+ end
64
+ end
65
+ end
@@ -4,11 +4,19 @@ module Ransack
4
4
  alias_method :ransack_condition_build, :build
5
5
 
6
6
  def build(params)
7
- decoded_attr_names = []
8
- params[:a].each do |possible_abbr|
9
- decoded_attr_names << @context.decode_parameter(possible_abbr)
7
+ attrs = params[:a]
8
+ unless attrs.blank?
9
+ case attrs
10
+ when Array
11
+ attrs.each_with_index do |attr, i|
12
+ params[:a][i] = @context.decode_parameter(attr)
13
+ end
14
+ when Hash
15
+ attrs.each do |index, attr|
16
+ params[:a][index][:name] = @context.decode_parameter(attr[:name])
17
+ end
18
+ end
10
19
  end
11
- params[:a] = decoded_attr_names
12
20
  ransack_condition_build(params)
13
21
  end
14
22
  end
@@ -1,3 +1,3 @@
1
1
  module RansackAbbreviator
2
- VERSION = "0.0.6"
2
+ VERSION = "0.0.7"
3
3
  end
@@ -0,0 +1,78 @@
1
+ require 'spec_helper'
2
+
3
+ module Ransack
4
+ module Helpers
5
+ describe FormBuilder do
6
+ # Below setup copied from Ransack 0.7.2 form_builder_spec
7
+ router = ActionDispatch::Routing::RouteSet.new
8
+ router.draw do
9
+ resources :people
10
+ match ':controller(/:action(/:id(.:format)))'
11
+ end
12
+
13
+ include router.url_helpers
14
+
15
+ # FIXME: figure out a cleaner way to get this behavior
16
+ before do
17
+ @controller = ActionView::TestCase::TestController.new
18
+ @controller.instance_variable_set(:@_routes, router)
19
+ @controller.class_eval do
20
+ include router.url_helpers
21
+ end
22
+
23
+ @controller.view_context_class.class_eval do
24
+ include router.url_helpers
25
+ end
26
+
27
+ @s = Person.search
28
+ @controller.view_context.search_form_for @s do |f|
29
+ @f = f
30
+ end
31
+ end
32
+
33
+ describe 'form helpers with abbreviations' do
34
+ it 'shortens the method to defined Ransack abbreviations' do
35
+ html = @f.abbr_label :name_eq
36
+ html.should match /for="q_nm_eq"/
37
+
38
+ html = @f.abbr_select :children_name_eq, "<option value=\"Ernie\">Ernie</option><option value=\"Bob\">Bob</option>"
39
+ html.should match /id="q_ch.nm_eq"/
40
+ end
41
+
42
+ it 'uses the full name for undefined abbreviations' do
43
+ html = @f.abbr_text_area :articles_body_cont
44
+ html.should match /id="q_articles.body_cont"/
45
+ end
46
+
47
+ it 'selects previously-entered values' do
48
+ @s.name_eq = 'Ernie'
49
+ html = @f.abbr_text_field :name_eq
50
+ html.should match /value="Ernie"/
51
+
52
+ @s.children_name_eq = 'Ernie'
53
+ html = @f.abbr_text_field :children_name_eq
54
+ html.should match /value="Ernie"/
55
+ end
56
+ end
57
+
58
+ describe '#abbr_attribute_select' do
59
+ it 'returns ransackable attributes as abbreviations' do
60
+ html = @f.abbr_attribute_select
61
+ html.split(/\n/).should have(Person.ransackable_attributes.size + 1).lines
62
+ Person.ransackable_attributes.each do |attribute|
63
+ html.should match /<option value="#{@s.context.encode_parameter(attribute)}">/
64
+ end
65
+ end
66
+
67
+ it 'returns ransackable attributes as abbreviations for associations' do
68
+ attributes = Person.ransackable_attributes + Comment.ransackable_attributes.map {|a| "authored_article_comments_#{a}"}
69
+ html = @f.abbr_attribute_select :associations => ['authored_article_comments']
70
+ html.split(/\n/).should have(attributes.size).lines
71
+ attributes.each do |attribute|
72
+ html.should match /<option value="#{@s.context.encode_parameter(attribute)}">/
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -123,6 +123,7 @@ module Ransack # We're testing Ransack's Search wih abbreviations
123
123
  end
124
124
 
125
125
  context "without abbreviations" do
126
+ # Below specs copied from Ransack 0.7.2 search_spec. I'm ensuring I didn't break any existing Ransack functionality
126
127
  it 'creates Conditions for top-level attributes' do
127
128
  search = Search.new(Person, :name_eq => 'Ernie')
128
129
  condition = search.base[:name_eq]
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: ransack_abbreviator
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.6
5
+ version: 0.0.7
6
6
  platform: ruby
7
7
  authors:
8
8
  - Jamie Davidson
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2013-02-05 00:00:00 Z
13
+ date: 2013-02-08 00:00:00 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: ransack
@@ -104,6 +104,7 @@ files:
104
104
  - lib/ransack_abbreviator/constants.rb
105
105
  - lib/ransack_abbreviator/engine.rb
106
106
  - lib/ransack_abbreviator/ransack_extensions/context.rb
107
+ - lib/ransack_abbreviator/ransack_extensions/helpers/form_builder.rb
107
108
  - lib/ransack_abbreviator/ransack_extensions/nodes/condition.rb
108
109
  - lib/ransack_abbreviator/ransack_extensions/search.rb
109
110
  - lib/ransack_abbreviator/version.rb
@@ -117,6 +118,7 @@ files:
117
118
  - spec/ransack_abbreviator/adapters/active_record/base_spec.rb
118
119
  - spec/ransack_abbreviator/configuration_spec.rb
119
120
  - spec/ransack_abbreviator/helper_spec.rb
121
+ - spec/ransack_abbreviator/helpers/form_builder_spec.rb
120
122
  - spec/ransack_abbreviator/search_spec.rb
121
123
  - spec/spec_helper.rb
122
124
  - spec/support/schema.rb
@@ -156,6 +158,7 @@ test_files:
156
158
  - spec/ransack_abbreviator/adapters/active_record/base_spec.rb
157
159
  - spec/ransack_abbreviator/configuration_spec.rb
158
160
  - spec/ransack_abbreviator/helper_spec.rb
161
+ - spec/ransack_abbreviator/helpers/form_builder_spec.rb
159
162
  - spec/ransack_abbreviator/search_spec.rb
160
163
  - spec/spec_helper.rb
161
164
  - spec/support/schema.rb