power_resource 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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