puffer 0.0.32 → 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 (117) hide show
  1. data/.gitignore +7 -0
  2. data/Gemfile +1 -26
  3. data/Gemfile.lock +66 -64
  4. data/README.md +34 -23
  5. data/Rakefile +1 -11
  6. data/VERSION +1 -1
  7. data/app/assets/javascripts/puffer/application.js +6 -1
  8. data/app/assets/javascripts/puffer/associations.js +18 -0
  9. data/app/assets/javascripts/puffer/puffer.js +7 -0
  10. data/app/assets/javascripts/puffer/right-calendar-src.js +19 -3
  11. data/app/assets/javascripts/puffer/right-dnd-src.js +591 -0
  12. data/app/assets/javascripts/puffer/right-in-edit-src.js +373 -0
  13. data/app/assets/javascripts/puffer/right-keys-src.js +87 -0
  14. data/app/assets/javascripts/puffer/{paginator.js → right-paginator-src.js} +0 -0
  15. data/app/assets/javascripts/puffer/right-slider-src.js +29 -32
  16. data/app/assets/javascripts/puffer/right-sortable-src.js +430 -0
  17. data/app/assets/javascripts/puffer/right-src.js +358 -99
  18. data/app/assets/stylesheets/puffer/puffer.css +29 -4
  19. data/app/components/base/form.html.erb +8 -14
  20. data/app/components/base_component.rb +1 -1
  21. data/app/components/boolean/form.html.erb +5 -3
  22. data/app/components/boolean/index.html.erb +6 -2
  23. data/app/components/boolean_component.rb +2 -2
  24. data/app/components/date_time/filter.html.erb +9 -0
  25. data/app/components/date_time/form.html.erb +8 -4
  26. data/app/components/date_time_component.rb +21 -5
  27. data/app/components/file/form.html.erb +8 -4
  28. data/app/components/hidden/form.html.erb +3 -1
  29. data/app/components/nested_attributes_many/form.html.erb +47 -0
  30. data/app/components/nested_attributes_many_component.rb +7 -0
  31. data/app/components/nested_attributes_one/form.html.erb +48 -0
  32. data/app/components/nested_attributes_one_component.rb +7 -0
  33. data/app/components/password/form.html.erb +8 -4
  34. data/app/components/password_component.rb +1 -1
  35. data/app/components/references_many/index.html.erb +1 -1
  36. data/app/components/references_one/choose.html.erb +1 -1
  37. data/app/components/references_one/form.html.erb +10 -9
  38. data/app/components/references_one_component.rb +0 -1
  39. data/app/components/render_component.rb +13 -0
  40. data/app/components/select/filter.html.erb +4 -2
  41. data/app/components/select/form.html.erb +8 -4
  42. data/app/components/text/form.html.erb +8 -4
  43. data/app/controllers/admin/sessions_controller.rb +1 -21
  44. data/app/controllers/puffer/base.rb +10 -3
  45. data/app/controllers/puffer/dashboard_base.rb +7 -1
  46. data/app/controllers/puffer/{sessions_base.rb → sessions/base.rb} +10 -7
  47. data/app/controllers/puffer/sessions/clearance.rb +29 -0
  48. data/app/controllers/puffer/{sessions_devise_base.rb → sessions/devise.rb} +1 -1
  49. data/app/controllers/puffer/sessions/simple.rb +28 -0
  50. data/app/controllers/puffer/tree_base.rb +1 -1
  51. data/app/models/puffer_user.rb +3 -0
  52. data/app/views/layouts/puffer.html.erb +3 -3
  53. data/app/views/puffer/base/_edit.html.erb +15 -0
  54. data/app/views/puffer/base/_index.html.erb +26 -0
  55. data/app/views/puffer/base/_show.html.erb +13 -0
  56. data/app/views/puffer/base/_table.html.erb +1 -1
  57. data/app/views/puffer/base/edit.html.erb +1 -15
  58. data/app/views/puffer/base/edit.js.erb +1 -0
  59. data/app/views/puffer/base/index.html.erb +1 -20
  60. data/app/views/puffer/base/index.js.erb +1 -0
  61. data/app/views/puffer/base/new.html.erb +1 -1
  62. data/app/views/puffer/base/show.html.erb +1 -22
  63. data/app/views/puffer/base/show.js.erb +1 -0
  64. data/app/views/puffer/base/update.js.erb +1 -0
  65. data/app/views/puffer/sessions/base/new.html.erb +11 -0
  66. data/app/views/puffer/tree_base/_record.html.erb +1 -1
  67. data/lib/puffer/component.rb +14 -47
  68. data/lib/puffer/controller/auth.rb +13 -9
  69. data/lib/puffer/controller/config.rb +18 -0
  70. data/lib/puffer/controller/mutate.rb +8 -8
  71. data/lib/puffer/engine.rb +5 -0
  72. data/lib/puffer/field.rb +5 -11
  73. data/lib/puffer/filters.rb +86 -56
  74. data/lib/puffer/helpers/component_helper.rb +24 -0
  75. data/lib/puffer/helpers/puffer_helper.rb +65 -0
  76. data/lib/puffer/helpers/puffer_tree_helper.rb +19 -0
  77. data/lib/puffer/orm_adapter/active_record.rb +40 -11
  78. data/lib/puffer/orm_adapter/base.rb +9 -0
  79. data/lib/puffer/orm_adapter/mongoid.rb +32 -9
  80. data/lib/puffer/resource/node.rb +2 -2
  81. data/lib/puffer/resource/routing.rb +30 -16
  82. data/lib/puffer/resource.rb +20 -20
  83. data/lib/puffer/version.rb +3 -0
  84. data/lib/puffer.rb +26 -5
  85. data/puffer.gemspec +34 -296
  86. data/spec/app/components/base_component_spec.rb +1 -1
  87. data/spec/app/components/boolean_component_spec.rb +2 -0
  88. data/spec/app/components/date_time_component_spec.rb +1 -0
  89. data/spec/app/components/file_component_spec.rb +1 -0
  90. data/spec/app/components/hidden_component_spec.rb +1 -0
  91. data/spec/app/components/password_component_spec.rb +2 -0
  92. data/spec/app/components/select_component_spec.rb +1 -0
  93. data/spec/app/components/string_component_spec.rb +1 -0
  94. data/spec/app/components/text_component_spec.rb +1 -0
  95. data/spec/dummy/app/controllers/admin/news_controller.rb +2 -0
  96. data/spec/dummy/app/controllers/admin/profiles_controller.rb +1 -1
  97. data/spec/dummy/app/controllers/admin/users_controller.rb +2 -0
  98. data/spec/dummy/app/controllers/orms/active_record_orm_primals_controller.rb +8 -0
  99. data/spec/dummy/app/helpers/news_helper.rb +7 -0
  100. data/spec/dummy/app/models/active_record_orm/has_many_reference.rb +5 -0
  101. data/spec/dummy/app/models/active_record_orm/has_one_reference.rb +5 -0
  102. data/spec/dummy/app/models/active_record_orm/primal.rb +4 -0
  103. data/spec/dummy/config/environments/development.rb +1 -1
  104. data/spec/dummy/db/migrate/20111120144025_create_active_record_orm_has_one_references.rb +10 -0
  105. data/spec/dummy/db/migrate/20111122203304_create_active_record_orm_has_many_references.rb +10 -0
  106. data/spec/dummy/db/schema.rb +15 -1
  107. data/spec/helpers/puffer_helper_spec.rb +1 -1
  108. data/spec/lib/fields_spec.rb +0 -9
  109. data/spec/lib/filters_spec.rb +4 -8
  110. data/spec/lib/orm_adapter/base_shared.rb +22 -0
  111. data/spec/spec_helper.rb +1 -1
  112. metadata +89 -60
  113. data/app/components/string/form.html.erb +0 -5
  114. data/app/helpers/puffer_helper.rb +0 -51
  115. data/app/helpers/puffer_tree_helper.rb +0 -15
  116. data/app/views/puffer/sessions_base/new.html.erb +0 -11
  117. data/lib/puffer/extensions/form.rb +0 -16
@@ -1,40 +1,103 @@
1
1
  module Puffer
2
2
  class Filters
3
+ class Diapason < Struct.new(:from, :till)
4
+ def empty?
5
+ from.blank? && till.blank?
6
+ end
7
+
8
+ def persisted?
9
+ false
10
+ end
11
+
12
+ def to_query(key)
13
+ {:from => from, :till => till}.to_query(key)
14
+ end
15
+ end
16
+
3
17
  include ActiveModel::Conversion
4
18
  extend ActiveModel::Naming
5
19
  extend ActiveModel::Translation
6
20
  include ActiveModel::AttributeMethods
7
21
 
8
- delegate :model_name, :to => 'self.class'
22
+ delegate :model_name, :special_attributes, :to => 'self.class'
9
23
 
10
- def initialize attributes = {}
11
- attributes ||= {}
12
- attributes.each do |(key, value)|
13
- send("#{key}=", value) if respond_to?("#{key}=")
24
+ def self.special_attributes
25
+ %w(puffer_search puffer_order)
26
+ end
27
+
28
+ special_attributes.each do |attribute|
29
+ define_method attribute do
30
+ read_attribute attribute
31
+ end
32
+ define_method "#{attribute}=" do |value|
33
+ write_attribute attribute, value
14
34
  end
15
35
  end
16
36
 
37
+ attr_reader :fieldset
38
+
39
+ def initialize fieldset, attributes = {}
40
+ @attributes = {}
41
+ @fieldset = fieldset
42
+ generate_attribute_methods
43
+
44
+ self.attributes = attributes
45
+ end
46
+
17
47
  def read_attribute name
18
- attributes[name]
48
+ @attributes[name.to_s]
19
49
  end
20
50
 
21
51
  def write_attribute name, value
22
- attributes[name] = value.presence if attributes.key?(name)
52
+ if value.is_a? Hash
53
+ value.each do |key, subvalue|
54
+ @attributes[name.to_s][key] = subvalue if subvalue.present?
55
+ end
56
+ else
57
+ @attributes[name.to_s] = value
58
+ end if value.present?
23
59
  end
24
60
 
25
- def persisted?
26
- false
61
+ def any?
62
+ attributes.values.any?
27
63
  end
28
64
 
29
- def any?
30
- attributes.keys.any? { |attribute| !send(attribute).nil? }
65
+ def attributes
66
+ (fieldset.map(&:field_name) + special_attributes).reduce(ActiveSupport::HashWithIndifferentAccess.new()) do |res, attribute|
67
+ res.merge attribute => send(attribute)
68
+ end
69
+ end
70
+
71
+ def attributes= attributes = {}
72
+ attributes.each do |(key, value)|
73
+ send("#{key}=", value) if respond_to?("#{key}=")
74
+ end
75
+ end
76
+
77
+ def generate_attribute_methods
78
+ fieldset.each do |field|
79
+ define_singleton_method :"#{field}" do
80
+ read_attribute field
81
+ end
82
+ define_singleton_method :"#{field}=" do |value|
83
+ write_attribute field, value
84
+ end
85
+
86
+ if %(date, time, datetime, date_time, timestamp).include?(field.type.to_s)
87
+ @attributes[field.to_s] = Puffer::Filters::Diapason.new
88
+
89
+ define_singleton_method :"#{field}_attributes=" do |value|
90
+ write_attribute field, value
91
+ end
92
+ end
93
+ end
31
94
  end
32
95
 
33
96
  def conditions
34
- attributes.except('puffer_search', 'puffer_order').keys.reduce({}) do |res, attribute|
97
+ fieldset.map(&:field_name).reduce(ActiveSupport::HashWithIndifferentAccess.new()) do |res, attribute|
35
98
  value = send(attribute)
36
99
 
37
- unless value.nil?
100
+ unless value.blank?
38
101
  value = case value
39
102
  when 'puffer_nil' then nil
40
103
  when 'puffer_blank' then ''
@@ -52,54 +115,21 @@ module Puffer
52
115
  end
53
116
 
54
117
  def order
55
- puffer_order
118
+ puffer_order.to_s.split(' ').map(&:to_sym)
56
119
  end
57
120
 
58
- module ClassMethods
59
- def model_name
60
- @model_name ||= begin
61
- name = super
62
- name.instance_variable_set :@param_key, 'filters'
63
- name
64
- end
65
- end
66
-
67
- def controller_filters controller
68
- scope = "#{controller}Filters".split('::')[0..-2].join('::').constantize rescue Kernel
69
- name = "#{controller}Filters".demodulize
70
-
71
- if scope.const_defined?(name)
72
- scope.const_get(name)
73
- else
74
- attributes_from_controller = controller.index_fields.reduce({}) do |res, field|
75
- res[field.field_name] = nil
76
- res
77
- end
78
-
79
- attributes_from_controller.merge!('puffer_search' => nil, 'puffer_order' => nil)
80
-
81
- klass = Class.new(self)
82
-
83
- attributes_from_controller.keys.each do |name|
84
- klass.send :define_method, name do
85
- read_attribute name
86
- end
87
- klass.send :define_method, "#{name}=" do |value|
88
- write_attribute name, value
89
- end
90
- end
91
-
92
- klass.send :define_method, :attributes do
93
- attributes_from_controller
94
- end
95
-
96
-
97
- scope.const_set(name, klass)
98
- end
121
+ def query
122
+ (fieldset.map(&:field_name) + special_attributes).reduce(ActiveSupport::HashWithIndifferentAccess.new()) do |res, attribute|
123
+ value = send(attribute)
124
+ attribute = "#{attribute}_attributes" if respond_to?("#{attribute}_attributes=")
125
+ res[attribute] = value if value.present?
126
+ res
99
127
  end
100
128
  end
101
129
 
102
- extend ClassMethods
130
+ def persisted?
131
+ false
132
+ end
103
133
 
104
134
  end
105
135
  end
@@ -0,0 +1,24 @@
1
+ module Puffer
2
+ module Helpers
3
+ module ComponentHelper
4
+
5
+ def component_wrap name = :span, options = {}, &block
6
+ content_tag name, options.merge(:id => component_id), &block
7
+ end
8
+
9
+ def paginate(scope, options = {}, &block)
10
+ paginator = Kaminari::Helpers::Paginator.new parent_controller.view_context, options.reverse_merge(:current_page => scope.current_page, :num_pages => scope.num_pages, :per_page => scope.limit_value, :param_name => Kaminari.config.param_name, :remote => false)
11
+ paginator.to_s
12
+ end
13
+
14
+ def component_fields_for record, &block
15
+ if opts[:builder]
16
+ capture opts[:builder], &block
17
+ else
18
+ fields_for record, &block
19
+ end
20
+ end
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,65 @@
1
+ # coding: utf-8
2
+
3
+ module Puffer
4
+ module Helpers
5
+ module PufferHelper
6
+
7
+ def puffer_scopes_navigation
8
+ Rails.application.routes.resources_tree.map(&:scope).uniq.each do |scope|
9
+ yield scope, send("#{scope}_root_path"), scope == puffer_namespace
10
+ end
11
+ end
12
+
13
+ def puffer_groups_navigation namespace = puffer_namespace
14
+ Rails.application.routes.resources_tree.roots.select {|node| node.scope == namespace}.uniq_by(&:group).each do |resource_node|
15
+ if resource_node.group
16
+ path = send("#{resource_node.scope}_#{resource_node.url_segment}_path")
17
+ current = resource.resource_node ? resource.root.resource_node.group == resource_node.group : false
18
+
19
+ yield resource_node.group, path, current
20
+ end
21
+ end
22
+ end
23
+
24
+ def puffer_resources_navigation namespace = puffer_namespace, group = configuration.group
25
+ Rails.application.routes.resources_tree.roots.select {|node| node.scope == namespace && node.group == group}.each do |resource_node|
26
+ title = resource_node.controller.model.model_name.human
27
+ path = send("#{resource_node.scope}_#{resource_node.url_segment}_path")
28
+ current = resource.resource_node ? resource.root.resource_node == resource_node : false
29
+
30
+ yield title, path, current
31
+ end
32
+ end
33
+
34
+ def render_head field
35
+ head = []
36
+ if field.column
37
+ head.push link_to_unless(puffer_filters.puffer_order == field.to_s, "▼", resource.collection_path(:page => params[:page], Puffer::Filters.model_name.param_key => puffer_filters.query.merge(:puffer_order => field)))
38
+ head.push link_to_unless(puffer_filters.puffer_order == [field, :desc].join(' '), "▲", resource.collection_path(:page => params[:page], Puffer::Filters.model_name.param_key => puffer_filters.query.merge(:puffer_order => [field, :desc].join(' '))))
39
+ end
40
+ head.push field.human
41
+ head.join(' ').html_safe
42
+ end
43
+
44
+ def render_field field, record
45
+ if field.options[:render]
46
+ case field.options[:render]
47
+ when Symbol then
48
+ res = send(field.options[:render], record)
49
+ when Proc then
50
+ res = field.options[:render].bind(self).call(record)
51
+ else ''
52
+ end
53
+ else
54
+ res = record.call_chain(field.to_s)
55
+ end
56
+ unless field.native?
57
+ url = edit_polymorphic_path [resource.scope, record.call_chain(field.path)] rescue nil
58
+ res = link_to res, url if url
59
+ end
60
+ res
61
+ end
62
+
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,19 @@
1
+ module Puffer
2
+ module Helpers
3
+ module PufferTreeHelper
4
+
5
+ def puffer_tree hash, options = {}, &block
6
+ content_tag :ul, options do
7
+ puffer_tree_node hash, &block
8
+ end if hash.present?
9
+ end
10
+
11
+ def puffer_tree_node hash, &block
12
+ hash.keys.each do |node|
13
+ block.call node, render_tree(hash[node], &block)
14
+ end if hash.present?
15
+ end
16
+
17
+ end
18
+ end
19
+ end
@@ -8,23 +8,40 @@ module Puffer
8
8
  end
9
9
  end
10
10
 
11
+ def reflection name
12
+ reflection = klass.reflect_on_association(name.to_sym)
13
+ Reflection.new(
14
+ :klass => reflection.klass,
15
+ :macro => reflection.macro,
16
+ :through? => !!reflection.through_reflection
17
+ ) if reflection
18
+ end
19
+
11
20
  def filter scope, fields, options = {}
12
- fields = fields.columns
13
21
  conditions, order = extract_conditions_and_order!(options)
14
22
 
15
- conditions_fields = fields.select {|f| conditions.keys.include?(f.field_name)}.to_fieldset
16
- search_fields = fields.select {|f| !conditions_fields.include?(f) && search_types.include?(f.column_type)}
17
- all_fields = conditions_fields + search_fields
23
+ order = order.map { |name, dir| field = fields[name]; "#{query_order(field)} #{dir}" if field && field.column }.compact.join(', ')
24
+
25
+ conditions_fields = fields.select {|f| f.column && conditions.keys.include?(f.field_name)}.to_fieldset
26
+ search_fields = fields.select {|f| f.column && !conditions_fields.include?(f) && search_types.include?(f.column_type)}
27
+ all_fields = conditions_fields + search_fields
18
28
 
19
- conditions = conditions.reduce({}) do |res, (name, value)|
29
+ scope = scope.includes(includes(all_fields)).includes(reflection_includes(fields)).where(searches(search_fields, options[:search])).order(order)
30
+
31
+ conditions.each do |name, value|
20
32
  field = conditions_fields[name]
21
- res[field.query_column] = value if field
22
- res
33
+ scope = if value.is_a?(Puffer::Filters::Diapason)
34
+ case
35
+ when value.from.blank? then scope.where(["#{query_column(field)} < ?", value.till])
36
+ when value.till.blank? then scope.where(["#{query_column(field)} > ?", value.from])
37
+ else scope.where(name => Range.new(value.from, value.till))
38
+ end
39
+ else
40
+ scope.where(name => value)
41
+ end if field
23
42
  end
24
43
 
25
- order = order.map {|field, direction| "#{field} #{direction}"}.join(', ')
26
-
27
- scope.includes(includes(all_fields)).where(searches(search_fields, options[:search])).where(conditions).order(order)
44
+ scope
28
45
  end
29
46
 
30
47
  private
@@ -37,8 +54,20 @@ module Puffer
37
54
  fields.map {|f| f.path unless f.native?}.compact.to_includes
38
55
  end
39
56
 
57
+ def reflection_includes fields
58
+ fields.map {|f| f.field_name if f.reflection}.compact.to_includes
59
+ end
60
+
40
61
  def searches fields, query
41
- [fields.map {|f| "#{f.query_column} like ?"}.compact.join(' or '), *(Array.wrap("%#{query}%") * fields.count)] if query.present?
62
+ [fields.map {|f| "#{query_column(f)} like ?"}.compact.join(' or '), *(Array.wrap("%#{query}%") * fields.count)] if query.present?
63
+ end
64
+
65
+ def query_column field
66
+ "#{field.model.table_name}.#{field.name}" if field.column
67
+ end
68
+
69
+ def query_order field
70
+ field.options[:order] || query_column(field)
42
71
  end
43
72
 
44
73
  end
@@ -11,6 +11,15 @@ module Puffer
11
11
  end
12
12
 
13
13
  end
14
+
15
+ class Reflection < ActiveSupport::OrderedOptions
16
+
17
+ def initialize hash
18
+ super
19
+ hash.each { |(key, value)| self[key] = value }
20
+ end
21
+
22
+ end
14
23
  end
15
24
  end
16
25
 
@@ -8,22 +8,41 @@ module Puffer
8
8
  end
9
9
  end
10
10
 
11
+ def reflection name
12
+ reflection = klass.reflect_on_association(name.to_sym)
13
+ Reflection.new(
14
+ :klass => reflection.klass,
15
+ :macro => reflection.macro,
16
+ :through? => false
17
+ ) if reflection
18
+ end
19
+
11
20
  def filter scope, fields, options = {}
12
- fields = fields.columns
13
21
  conditions, order = extract_conditions_and_order!(options)
14
22
 
15
- conditions_fields = fields.select {|f| conditions.keys.include?(f.field_name)}.to_fieldset
16
- search_fields = fields.select {|f| !conditions_fields.include?(f) && search_types.include?(f.column_type)}
23
+ order = order.map { |o| f = fields[o.first]; [query_order(f), o.last] if f && f.column }.compact
24
+
25
+ conditions_fields = fields.select {|f| f.column && conditions.keys.include?(f.field_name)}.to_fieldset
26
+ search_fields = fields.select {|f| f.column && !conditions_fields.include?(f) && search_types.include?(f.column_type)}
17
27
  all_fields = conditions_fields + search_fields
28
+
29
+ scope = scope.any_of(searches(search_fields, options[:search])) if options[:search].present?
30
+ scope = scope.order_by(order)
18
31
 
19
- conditions = conditions.reduce({}) do |res, (name, value)|
32
+ conditions.each do |name, value|
20
33
  field = conditions_fields[name]
21
- res[field.name] = value if field
22
- res
34
+ scope = if value.is_a?(Puffer::Filters::Diapason)
35
+ case
36
+ when value.from.blank? then scope.where(name.to_sym.lt => value.till)
37
+ when value.till.blank? then scope.where(name.to_sym.gt => value.from)
38
+ else scope.where(name => Range.new(value.from, value.till))
39
+ end
40
+ else
41
+ scope.where(name => value)
42
+ end if field
23
43
  end
24
44
 
25
- scope = scope.any_of(searches(search_fields, options[:search])) if options[:search].present?
26
- scope.where(conditions).order(order)
45
+ scope
27
46
  end
28
47
 
29
48
  private
@@ -34,7 +53,11 @@ module Puffer
34
53
 
35
54
  def searches fields, query
36
55
  regexp = /#{Regexp.escape(query)}/i
37
- fields.map {|field| {field.name => regexp}}
56
+ fields.map {|field| {field.to_s => regexp}}
57
+ end
58
+
59
+ def query_order field
60
+ field.options[:order] || field.name
38
61
  end
39
62
 
40
63
  end
@@ -59,8 +59,8 @@ module Puffer
59
59
  ancestors
60
60
  end
61
61
 
62
- def url_string
63
- [scope, name, (:index if singular == plural)].compact.map(&:to_s).join('_')
62
+ def url_segment
63
+ [name, (:index if singular == plural)].compact.map(&:to_s).join('_')
64
64
  end
65
65
 
66
66
  def to_struct
@@ -5,38 +5,52 @@ module Puffer
5
5
  include ActionController::UrlFor
6
6
  include Rails.application.routes.url_helpers
7
7
 
8
- def collection_url *args
9
- polymorphic_url *route_args(route_member(model), *args)
8
+ def collection_method routing_type, options = {}
9
+ send url_method_name(routing_type, url_segment, options.delete(:action)), *url_arguments, options
10
10
  end
11
11
 
12
- def member_url *args
13
- suggest = args.shift if args.first.respond_to? :to_key
14
- polymorphic_url *route_args(route_member(suggest), *args)
12
+ def member_method routing_type, *args
13
+ options = args.extract_options!
14
+ send url_method_name(routing_type, singular, options.delete(:action)), *url_arguments(use_resource_id(args.first) || member_id), options
15
15
  end
16
16
 
17
- def new_url *args
18
- new_polymorphic_url *route_args(name.to_s.singularize, *args)
17
+ def new_method routing_type, options = {}
18
+ send url_method_name(routing_type, singular, :new), *url_arguments, options
19
19
  end
20
20
 
21
- def edit_url *args
22
- suggest = args.shift if args.first.respond_to? :to_key
23
- edit_polymorphic_url *route_args(route_member(suggest), *args)
21
+ def edit_method routing_type, *args
22
+ options = args.extract_options!
23
+ member_method routing_type, *args, options.merge(:action => :edit)
24
24
  end
25
25
 
26
- def route_args *args
27
- options = args.extract_options!
28
- resource = Array.wrap(args)
29
- return [scope] + ancestors.map(&:route_member) + resource, options
26
+ def url_method_name routing_type, current, action = nil
27
+ [action, scope, *ancestors.map(&:singular), current, routing_type].compact.join('_')
30
28
  end
31
29
 
32
- def route_member suggest = nil
33
- plural? ? (suggest || member) : name.to_s.singularize
30
+ def url_arguments current = nil
31
+ ancestors.map(&:member_id).push(current).compact
32
+ end
33
+
34
+ %w(url path).each do |routing_type|
35
+ %w(collection member new edit).each do |method|
36
+ define_method "#{method}_#{routing_type}" do |*args|
37
+ send "#{method}_method", routing_type, *args
38
+ end
39
+ end
34
40
  end
35
41
 
36
42
  def default_url_options *args
37
43
  Puffer::Base.default_url_options(*args)
38
44
  end
39
45
 
46
+ def use_resource_id(resource)
47
+ if resource and resource.respond_to?(:id)
48
+ resource.id
49
+ else
50
+ resource
51
+ end
52
+ end
53
+
40
54
  end
41
55
  end
42
56
  end
@@ -11,7 +11,7 @@ module Puffer
11
11
  include Routing
12
12
 
13
13
  attr_reader :resource_node, :scope, :params, :controller_instance
14
- delegate :controller, :name, :plural?, :to => :resource_node, :allow_nil => true
14
+ delegate :controller, :name, :plural?, :singular, :plural, :url_segment, :to => :resource_node, :allow_nil => true
15
15
  delegate :model, :to => :controller, :allow_nil => true
16
16
  delegate :env, :request, :to => :controller_instance, :allow_nil => true
17
17
 
@@ -51,14 +51,10 @@ module Puffer
51
51
  resource_node.ancestors[0..-2].each do |ancestor|
52
52
  key = ancestor.to_s.singularize.foreign_key
53
53
  parent_params[key] = params[key] if params[key]
54
- key = key.gsub(/_id$/, '_member')
55
- parent_params[key] = params[key] if params[key]
56
54
  end
57
55
 
58
56
  key = resource_node.parent.to_s.singularize.foreign_key
59
57
  parent_params[:id] = params[key] if params[key]
60
- key = key.gsub(/_id$/, '_member')
61
- parent_params[:member] = params[key] if params[key]
62
58
 
63
59
  self.class.new parent_params, controller_instance
64
60
  end
@@ -72,14 +68,10 @@ module Puffer
72
68
  resource_node.ancestors.each do |ancestor|
73
69
  key = ancestor.to_s.singularize.foreign_key
74
70
  child_params[key] = params[key] if params[key]
75
- key = key.gsub(/_id$/, '_member')
76
- child_params[key] = params[key] if params[key]
77
71
  end
78
72
 
79
73
  key = resource_node.to_s.singularize.foreign_key
80
74
  child_params[key] = params[:id] if params[:id]
81
- key = key.gsub(/_id$/, '_member')
82
- child_params[key] = params[:member] if params[:member]
83
75
 
84
76
  self.class.new child_params, controller_instance
85
77
  end
@@ -92,31 +84,40 @@ module Puffer
92
84
  end
93
85
  end
94
86
 
87
+ def member_id
88
+ params[:id]
89
+ end
90
+
95
91
  def collection_scope
96
92
  parent ? parent.member.send(name) : model
97
93
  end
98
94
 
95
+ def adapter
96
+ model.to_adapter
97
+ end
98
+
99
99
  def collection
100
- model.to_adapter.filter collection_scope, controller.index_fields,
100
+ scope = collection_scope
101
+ scope = scope.send controller.configuration.scope if controller.configuration.scope
102
+ adapter.filter scope, controller.filter_fields,
101
103
  :conditions => controller_instance.puffer_filters.conditions,
102
104
  :search => controller_instance.puffer_filters.search,
103
105
  :order => controller_instance.puffer_filters.order
104
106
  end
105
107
 
106
108
  def member
107
- return params[:member] if params[:member]
108
109
  if parent
109
110
  if plural?
110
- parent.member.send(name).find params[:id] if params[:id]
111
+ parent.member.send(name).find member_id if member_id
111
112
  else
112
113
  parent.member.send(name)
113
114
  end
114
115
  else
115
- model.find params[:id] if params[:id]
116
+ adapter.get member_id if member_id
116
117
  end
117
118
  end
118
119
 
119
- def new_member
120
+ def new_member attributes = attributes
120
121
  if parent
121
122
  if plural?
122
123
  parent.member.send(name).new attributes
@@ -129,15 +130,14 @@ module Puffer
129
130
  end
130
131
 
131
132
  def attributes
132
- params[name.to_s.singularize]
133
+ params[attributes_key] || {}
134
+ end
135
+
136
+ def attributes_key
137
+ model.model_name.param_key
133
138
  end
134
139
 
135
140
  def method_missing method, *args, &block
136
- method = method.to_s
137
- if method.match(/path$/) && respond_to?(method.gsub(/path$/, 'url'))
138
- options = args.extract_options!
139
- return send method.gsub(/path$/, 'url'), *(args << options.merge(:routing_type => :path))
140
- end
141
141
  model.send method, *args, &block if model.respond_to? method
142
142
  end
143
143
 
@@ -0,0 +1,3 @@
1
+ module Puffer
2
+ VERSION = "0.1.0"
3
+ end