power_resource 0.0.1 → 0.0.2

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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -2
  3. data/README.md +77 -10
  4. data/app/controllers/power_resource/base_controller.rb +19 -7
  5. data/app/helpers/power_resource/action_helper.rb +147 -0
  6. data/app/helpers/power_resource/base_helper.rb +51 -103
  7. data/app/helpers/power_resource/collection_helper.rb +20 -0
  8. data/app/helpers/power_resource/configuration_helper.rb +11 -0
  9. data/app/helpers/power_resource/rendering_helper.rb +26 -0
  10. data/app/views/power_resource/base/_actions.html.erb +3 -1
  11. data/app/views/power_resource/base/_collection.html.erb +5 -11
  12. data/app/views/power_resource/base/edit.html.erb +1 -1
  13. data/app/views/power_resource/base/index.html.erb +1 -1
  14. data/app/views/power_resource/base/new.html.erb +1 -1
  15. data/app/views/power_resource/builders/_form_for.html.erb +12 -3
  16. data/lib/power_resource.rb +1 -0
  17. data/lib/power_resource/configuration.rb +19 -0
  18. data/lib/power_resource/version.rb +1 -1
  19. data/power_resource.gemspec +9 -7
  20. data/spec/dummy/app/assets/javascripts/application.js +2 -0
  21. data/spec/dummy/app/assets/javascripts/categories.js +2 -0
  22. data/spec/dummy/app/assets/javascripts/comments.js +2 -0
  23. data/spec/dummy/app/assets/stylesheets/categories.css +4 -0
  24. data/spec/dummy/app/assets/stylesheets/comments.css +4 -0
  25. data/spec/dummy/app/controllers/backend/categories_controller.rb +7 -0
  26. data/spec/dummy/app/controllers/backend/comments_controller.rb +9 -0
  27. data/spec/dummy/app/controllers/backend/posts_controller.rb +7 -0
  28. data/spec/dummy/app/controllers/categories_controller.rb +5 -0
  29. data/spec/dummy/app/controllers/comments_controller.rb +7 -0
  30. data/spec/dummy/app/controllers/posts_controller.rb +3 -0
  31. data/spec/dummy/app/helpers/categories_helper.rb +2 -0
  32. data/spec/dummy/app/helpers/comments_helper.rb +2 -0
  33. data/spec/dummy/app/models/category.rb +5 -0
  34. data/spec/dummy/app/models/comment.rb +3 -0
  35. data/spec/dummy/app/models/post.rb +2 -0
  36. data/spec/dummy/app/views/layouts/application.html.erb +23 -11
  37. data/spec/dummy/config/initializers/secret_token.rb +1 -1
  38. data/spec/dummy/config/locales/en.yml +11 -22
  39. data/spec/dummy/config/locales/fi.yml +38 -0
  40. data/spec/dummy/config/routes.rb +13 -1
  41. data/spec/dummy/db/development.sqlite3 +0 -0
  42. data/spec/dummy/db/migrate/{20130722165046_create_posts.rb → 20130915095616_create_posts.rb} +1 -0
  43. data/spec/dummy/db/migrate/20130916174608_create_categories.rb +9 -0
  44. data/spec/dummy/db/migrate/20130916180755_create_comments.rb +11 -0
  45. data/spec/dummy/db/schema.rb +18 -1
  46. data/spec/dummy/db/test.sqlite3 +0 -0
  47. data/spec/dummy/log/development.log +17445 -674
  48. data/spec/dummy/log/test.log +20826 -2
  49. data/spec/features/posts_spec.rb +8 -0
  50. data/spec/helpers/action_helper_spec.rb +111 -0
  51. data/spec/helpers/base_helper_spec.rb +111 -1
  52. data/spec/helpers/collection_helper_spec.rb +53 -0
  53. data/spec/helpers/rendering_helper_spec.rb +162 -0
  54. data/spec/spec_helper.rb +11 -0
  55. metadata +92 -26
  56. data/app/views/power_resource/builders/_formtastic.html.erb +0 -4
  57. data/spec/dummy/spec/controllers/posts_controller_spec.rb +0 -5
  58. data/spec/dummy/spec/helpers/posts_helper_spec.rb +0 -15
  59. data/spec/dummy/spec/models/post_spec.rb +0 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9e0f9fc6dee728f9630996271a5beed85771e9cd
4
- data.tar.gz: d702eaa22dacbb157e5e1308c866a95eec5546fd
3
+ metadata.gz: 569c654414000d901c35f50fbd4b72bcff29baed
4
+ data.tar.gz: c1a14b6341b5cbb18c8f0e60cd4aec4d6c84137f
5
5
  SHA512:
6
- metadata.gz: fcf0b8d8ec2a666215b8cdc04bf719ffc41bb9e3b4fe383c70a9572c7cc7ed8a76738d21e5463f7bfc785ed3312afbc799cf46ff400c2b0fe977480a51b5835d
7
- data.tar.gz: 2644d8ca0872750688a129c21f2666f29fd07cdcc1ad2c4eac867e4bb2785befab282d2e7b54eb1931374d664c46c7d82de21a5c576e7fe46aba88b2edb59bbc
6
+ metadata.gz: f1b9342255ab6b0e122f6928d25e64b20ad2f016eb04d2f5189d5bf029d94377a46b96503140fb228b55f9601ec5c6802756a0ada36635d8e569f118d1b1c8f1
7
+ data.tar.gz: bab58253ced3a12c58d56318cfcdf4ac1a4a5f38203cf5be8725219ffb54b8422738f8d7b352b51d8b2ac3fa2bfe4162568de5139f8d1a28e0393bfa975323ea
data/Gemfile CHANGED
@@ -2,5 +2,5 @@ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'inherited_resources', github: 'josevalim/inherited_resources'
6
- gem 'formtastic'
5
+ gem 'jquery-rails' # Required for delete links
6
+
data/README.md CHANGED
@@ -1,13 +1,12 @@
1
1
  # PowerResource
2
2
 
3
- Power up your RESTful resources!
4
-
5
- ALPHA STAGE, DO NOT USE IN PRODUCTION!
3
+ Power up RESTful resources!
6
4
 
7
5
  ## Requirements
8
6
 
9
- * Ruby 2.0.0 or greater
10
- * Rails 4.0.0 or greater
7
+ * Ruby 2.0 or greater
8
+ * Rails 4.0 or greater
9
+ * Active Record 4.0 or greater
11
10
 
12
11
  ## Installation
13
12
 
@@ -25,22 +24,90 @@ Or install it yourself as:
25
24
 
26
25
  ## Usage
27
26
 
27
+ ### Basic Usage
28
+
28
29
  Inherit your resource controllers from PowerResource::BaseController:
29
30
 
30
- class ProductsController < PowerResource::BaseController
31
+ class PostsController < PowerResource::BaseController
32
+ end
33
+
34
+ ### Strong Parameters
35
+
36
+ Permit **only** title and content (recommended way):
37
+
38
+ class PostsController < PowerResource::BaseController
39
+ def permit_attributes
40
+ %w(title content)
41
+ end
42
+ end
43
+
44
+ Permit **all** attributes:
45
+
46
+ class PostsController < PowerResource::BaseController
47
+ def permit_attributes
48
+ resource_attributes
49
+ end
50
+ end
51
+
52
+ Permit all attributes **except** id:
53
+
54
+ class PostsController < PowerResource::BaseController
55
+ def permit_attributes
56
+ resource_attributes - %w(id)
57
+ end
58
+ end
59
+
60
+ Permit all **human-readable attributes** (all except id, created\_at and
61
+ updated\_at):
62
+
63
+ class PostsController < PowerResource::BaseController
64
+ def permit_attributes
65
+ resource_human_attributes
66
+ end
67
+ end
68
+
69
+ Permit all **human-readable attributes, except** title and content:
70
+
71
+ class PostsController < PowerResource::BaseController
72
+ def permit_attributes
73
+ resource_human_attributes - %w(title content)
74
+ end
75
+ end
76
+
77
+ Setting default behaviour can be done in ApplicationController:
78
+
79
+ class ApplicationController < ActionController::Base
80
+ def permit_attributes
81
+ resource_human_attributes
82
+ end
83
+ end
84
+
85
+ Also, you can use [Inherited Resources
86
+ way](https://github.com/josevalim/inherited_resources#strong-parameters) way:
87
+
88
+ class PostsController < PowerResource::BaseController
89
+ def permitted_params
90
+ params.permit(post: %w(title content))
91
+ end
31
92
  end
32
93
 
33
- ## Helpers
94
+ ### Helpers
34
95
 
35
- Besides all [helpers from Inherited Resources gem](https://github.com/josevalim/inherited_resources#url-helpers), next helper methods are available:
96
+ Besides all [helpers from Inherited Resources
97
+ gem](https://github.com/josevalim/inherited_resources#url-helpers), next helper
98
+ methods are available:
36
99
 
37
100
  resource_form_path #=> /products when creating a new resource
38
101
  #=> /products/1 when resource already exists
39
102
 
40
103
  ## Support
41
104
 
42
- If you have any questions or issues with PowerResource, or if you like to report a bug, please create an [issue on GitHub](https://github.com/jarijokinen/power_resource/issues).
105
+ If you have any questions or issues with PowerResource, or if you like to
106
+ report a bug, please create an [issue on
107
+ GitHub](https://github.com/jarijokinen/power_resource/issues).
43
108
 
44
109
  ## License
45
110
 
46
- MIT License. Copyright (c) 2013 [Jari Jokinen](http://jarijokinen.com). See [LICENSE](https://github.com/jarijokinen/power_resource/blob/master/LICENSE.txt) for further details.
111
+ MIT License. Copyright (c) 2013 [Jari Jokinen](http://jarijokinen.com). See
112
+ [LICENSE](https://github.com/jarijokinen/power_resource/blob/master/LICENSE.txt)
113
+ for further details.
@@ -3,6 +3,8 @@ module PowerResource
3
3
  inherit_resources
4
4
  defaults route_prefix: ''
5
5
 
6
+ include PowerResource::BaseHelper
7
+
6
8
  def create
7
9
  create! { collection_url }
8
10
  end
@@ -13,18 +15,28 @@ module PowerResource
13
15
 
14
16
  protected
15
17
 
16
- def resource_name
17
- controller_name.tableize.singularize.to_sym
18
+ def permit_attributes
19
+ # Override this method in your controller:
20
+ #
21
+ # class PostsController < PowerResource::BaseController
22
+ # def permit_attributes
23
+ # %w(title content)
24
+ # end
25
+ # end
26
+ #
27
+ # Or add default behaviour in your ApplicationController:
28
+ #
29
+ # class ApplicationController < ActionController::Base
30
+ # def permit_attributes
31
+ # resource_human_attributes
32
+ # end
33
+ # end
18
34
  end
19
35
 
20
36
  def permitted_params
21
37
  params.permit(
22
- resource_name => resource_class.attribute_names - denied_params
38
+ resource_name => permit_attributes
23
39
  )
24
40
  end
25
-
26
- def denied_params
27
- %w(id created_at updated_at)
28
- end
29
41
  end
30
42
  end
@@ -0,0 +1,147 @@
1
+ module PowerResource
2
+ module ActionHelper
3
+ # Returns humanized name for an action
4
+ #
5
+ # Customization using I18n API:
6
+ #
7
+ # power_resource:
8
+ # actions:
9
+ # new: 'New %{resource_name}'
10
+ # edit: 'Edit %{resource_name}'
11
+ # index: '%{collection_name}'
12
+ #
13
+ # Variables available in I18n:
14
+ #
15
+ # resource_name # => Post
16
+ # downcased_resource_name # => post
17
+ # collection_name # => Posts
18
+ #
19
+ # Examples:
20
+ #
21
+ # resource_action_human_name(:new)
22
+ # # => New Post
23
+ # resource_action_human_name(:edit)
24
+ # # => Edit Post
25
+ # resource_action_human_name(:duplicate)
26
+ # # => Duplicate Post
27
+ # resource_action_human_name(:index)
28
+ # # => Posts
29
+ #
30
+ def resource_action_human_name(action_name, options = {})
31
+ I18n.t("power_resource.resource_actions.#{action_name.to_s}",
32
+ {
33
+ resource_name: resource_human_name,
34
+ downcased_resource_name: resource_human_name.downcase,
35
+ collection_name: collection_human_name,
36
+ default: (action_name == :index ? collection_human_name :
37
+ "#{action_name.to_s.humanize} #{resource_human_name}")
38
+ }.merge(options))
39
+ end
40
+
41
+ # Returns a title for a current resource based on an action
42
+ #
43
+ # Customization using I18n API:
44
+ #
45
+ # power_resource:
46
+ # titles:
47
+ # post:
48
+ # new: 'New %{resource_name}'
49
+ # edit: 'Edit %{resource_name}'
50
+ # delete: 'Delete %{downcased_resource_name}'
51
+ # index: '%{collection_name}'
52
+ #
53
+ # Variables available in I18n:
54
+ #
55
+ # resource_name # => Post
56
+ # downcased_resource_name # => post
57
+ # collection_name # => Posts
58
+ #
59
+ # Examples:
60
+ #
61
+ # resource_action_title(:new)
62
+ # # => New Post
63
+ # resource_action_title(:edit)
64
+ # # => Edit Post
65
+ # resource_action_title(:duplicate)
66
+ # # => Duplicate Post
67
+ # resource_action_title(:index)
68
+ # # => Posts
69
+ #
70
+ def resource_action_title(action_name, options = {})
71
+ I18n.t("power_resource.titles.#{resource_name}.#{action_name.to_s}",
72
+ {
73
+ resource_name: resource_human_name,
74
+ downcased_resource_name: resource_human_name.downcase,
75
+ collection_name: collection_human_name,
76
+ default: resource_action_human_name(action_name, options)
77
+ }.merge(options))
78
+ end
79
+
80
+ # Returns a link for a current resource based on an action
81
+ #
82
+ # Customization using I18n API:
83
+ #
84
+ # power_resource:
85
+ # links:
86
+ # post:
87
+ # new: 'New %{resource_name}'
88
+ # edit: 'Edit'
89
+ # index: '%{collection_name}'
90
+ #
91
+ # Variables available in I18n:
92
+ #
93
+ # resource_name # => Post
94
+ # downcased_resource_name # => post
95
+ # collection_name # => Posts
96
+ #
97
+ # Examples:
98
+ #
99
+ # resource_link_to(:new)
100
+ # # => <a href="/posts/new">New Post</a>
101
+ # resource_link_to(:edit, resource)
102
+ # # => <a href="/posts/1/edit">Edit</a>
103
+ # resource_link_to(:index)
104
+ # # => <a href="/posts/">Posts</a>
105
+ #
106
+ def resource_link_to(action_name, resource_instance = nil)
107
+ if resource_instance
108
+ human_name = resource_human_name_for(resource_instance.class.name)
109
+ end
110
+
111
+ case action_name
112
+ when :show, :edit, :delete
113
+ default_text = I18n.t("power_resource.actions.#{action_name.to_s}",
114
+ default: action_name.to_s.humanize)
115
+ else
116
+ default_text = resource_action_human_name(action_name)
117
+ end
118
+
119
+ text = I18n.t("power_resource.links.#{resource_name}.#{action_name.to_s}",
120
+ {
121
+ resource_name: human_name || resource_human_name,
122
+ downcased_resource_name: human_name ? human_name.downcase :
123
+ resource_human_name.downcase,
124
+ collection_name: collection_human_name,
125
+ default: default_text
126
+ })
127
+
128
+ case action_name
129
+ when :index
130
+ link_to(text, collection_path)
131
+ when :show
132
+ link_to(text, resource_path(resource_instance || resource))
133
+ when :new
134
+ link_to(text, new_resource_path)
135
+ when :edit
136
+ link_to(text, edit_resource_path(resource_instance || resource),
137
+ class: collection_table_button_classes)
138
+ when :delete
139
+ link_to(text, resource_path(resource_instance || resource),
140
+ class: collection_table_button_classes,
141
+ method: :delete, data: {
142
+ confirm: I18n.t('power_resource.confirmations.delete',
143
+ default: 'Are you sure?') })
144
+ end
145
+ end
146
+ end
147
+ end
@@ -1,58 +1,62 @@
1
1
  module PowerResource
2
2
  module BaseHelper
3
- # Returns humanized and localized name for a current resource model
3
+ # Returns a name for a current resource
4
+ def resource_name
5
+ resource_class.to_s.tableize.singularize
6
+ end
7
+
8
+ # Returns humanized and localized name for a current resource
4
9
  def resource_human_name
5
10
  resource_class.model_name.human
6
11
  end
7
-
8
- # Returns humanized and localized name for a specified resource class
9
- def resource_human_name_for(resource_class_name)
10
- eval("#{resource_class_name.to_s.classify}.model_name.human")
11
- end
12
-
13
- # Returns an unique title for a resource
14
- def resource_title
15
- "#{resource_human_name} #{resource.id}"
12
+
13
+ # Returns humanized and localized name for a specific resource
14
+ def resource_human_name_for(resource_class_name, count = 1)
15
+ class_name = resource_class_name.to_s.classify
16
+ eval(class_name).model_name.human(count: count)
16
17
  end
17
18
 
18
- # Returns a title for a collection
19
- def collection_title
20
- I18n.t("activemodel.models.#{controller_name.singularize}.other",
21
- default: controller_name.humanize)
19
+ # Returns an unique title for a current resource
20
+ def resource_title(options = {})
21
+ I18n.t("power_resource.titles.#{resource_name}.resource",
22
+ { default: "#{resource_human_name} #{resource.id}" }.merge(options) )
22
23
  end
23
24
 
24
25
  # Returns all attributes for a resource
25
26
  def resource_attributes
26
27
  resource_class.attribute_names
27
28
  end
28
-
29
+
29
30
  # Returns attributes that should be invisible for end-users
30
- def non_human_attributes
31
- %w(id updated_at created_at)
31
+ def resource_non_human_attributes
32
+ %w(id created_at updated_at)
32
33
  end
33
-
34
+
34
35
  # Returns attributes for a resource without non-human attributes
35
36
  def resource_human_attributes
36
- human_attributes = resource_attributes - non_human_attributes
37
- if respond_to?("parent?")
37
+ human_attributes = resource_attributes - resource_non_human_attributes
38
+
39
+ # If resource has a belongs_to relationship, remove reference attribute
40
+ if respond_to?('parent?')
38
41
  parent_attribute = "#{parent.class.name.underscore}_id"
39
- human_attributes = human_attributes - ["#{parent_attribute}"]
42
+ human_attributes = human_attributes - [parent_attribute]
40
43
  end
44
+
41
45
  human_attributes
42
46
  end
43
47
 
44
48
  # Returns humanized and localized attribute name
45
- def attribute_human_name(attribute_name)
49
+ def resource_attribute_human_name_for(attribute_name)
46
50
  attribute_name = attribute_name.to_s
47
- I18n.t("activerecord.attributes.#{controller_name.singularize}.#{attribute_name}",
51
+ I18n.t("activerecord.attributes.#{resource_name}.#{attribute_name}",
48
52
  default: attribute_name.humanize)
49
53
  end
50
54
 
51
- # Returns truncated attribute value
52
- def attribute_value(resource, attribute_name, truncation = 50)
55
+ # Returns preformatted attribute value of a specific resource
56
+ def attribute_value_for(resource, attribute_name, truncation = 50)
53
57
  value = resource.send(attribute_name).to_s.truncate(truncation)
54
58
  if attribute_name.to_s.match(/_id$/)
55
- model_name = attribute_name.gsub(/_id$/, "").classify
59
+ model_name = attribute_name.gsub(/_id$/, '').classify
56
60
  begin
57
61
  value = eval(model_name).find(value).to_s
58
62
  rescue ActiveRecord::RecordNotFound
@@ -61,88 +65,32 @@ module PowerResource
61
65
  end
62
66
  value
63
67
  end
64
-
65
- # Returns a text based on action and resource names
66
- #
67
- # Example:
68
- #
69
- # resource_action(:new)
70
- # # => "New Product"
71
- def resource_action(action_name)
72
- I18n.t("power_resource.resource_actions.#{action_name}",
73
- resource_name: resource_human_name,
74
- default: "#{action_name.to_s.titleize} #{resource_human_name}")
75
- end
76
-
77
- # Returns a link for a resource
78
- #
79
- # Examples:
80
- #
81
- # resource_link(:new)
82
- # # => <a href="/products/new">New Product</a>
83
- # resource_link(:edit)
84
- # # => <a href="/products/1/edit">Edit Product</a>
85
- # resource_link(:edit, row)
86
- # # => <a href="/products/1/edit">Edit</a>
87
- # resource_link(:edit, text: "Make changes")
88
- # # => <a href="/products/1/edit">Make changes</a>
89
- def resource_link(action_name)
90
- text ||= resource_action(action_name)
91
-
92
- eval("resource_link_for_#{action_name.to_s}(text)")
93
-
94
- case action_name.to_sym
95
- when :new
96
- link_to(text, new_resource_path)
97
- when :edit
98
- link_to(text, edit_resource_path(resource))
99
- when :delete
100
- link_to
101
- end
102
- end
103
-
104
- # Returns form path for a resource
68
+
69
+ # Returns a form path for a resource
105
70
  def resource_form_path
106
71
  resource.new_record? ? collection_path : resource_path
107
72
  end
108
73
 
109
- # Renders form using selected form builder
110
- def render_form(form_builder = "formtastic")
111
- fields = resource_human_attributes
112
- fields.map! do |arg|
113
- arg.to_s.sub("_id", "").to_sym
74
+ # Returns associations for a resource
75
+ def resource_associations(association_type)
76
+ resource_class.reflect_on_all_associations(association_type).map(&:name)
77
+ end
78
+
79
+ # Returns association links for a resource
80
+ def resource_association_links_for(resource, options = {})
81
+ output = Array.new
82
+ resource_associations(:has_many).each do |association|
83
+ text = resource_human_name_for(association, 2)
84
+ if controller_path.include?('/')
85
+ namespace = controller.class.parent.name.underscore
86
+ path = [namespace, resource, association.to_s.tableize]
87
+ else
88
+ path = [resource, association.to_s.tableize]
89
+ end
90
+ options.merge!(class: collection_table_button_classes)
91
+ output << link_to(text, path, options)
114
92
  end
115
- render "power_resource/builders/#{form_builder}", fields: fields
116
- end
117
-
118
- # Renders collection table
119
- def render_collection_table(custom_attributes = nil)
120
- render "collection",
121
- collection: collection,
122
- attributes: custom_attributes || resource_human_attributes
123
- end
124
-
125
- # Renders action links for a resource
126
- def render_actions_for(resource)
127
- render "actions", resource: resource
128
- end
129
-
130
- private
131
-
132
- def resource_link_for_index(text)
133
- link_to(text, collection_path)
134
- end
135
-
136
- def resource_link_for_show(text)
137
- link_to(text, resource_path(resource))
138
- end
139
-
140
- def resource_link_for_new(text)
141
- link_to(text, new_resource_path)
142
- end
143
-
144
- def resource_link_for_edit(text)
145
- link_to(text, edit_resource_path(resource))
93
+ output.join(' ').html_safe
146
94
  end
147
95
  end
148
96
  end