smarter_listing 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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +77 -0
- data/Rakefile +32 -0
- data/app/views/smart_listing/_action_copy.html.erb +3 -0
- data/app/views/smarter_listing/_form_logic.js +1 -0
- data/app/views/smarter_listing/copy.js.erb +2 -0
- data/app/views/smarter_listing/create.js.erb +1 -0
- data/app/views/smarter_listing/destroy.js.erb +2 -0
- data/app/views/smarter_listing/edit.js.erb +2 -0
- data/app/views/smarter_listing/index.js.erb +1 -0
- data/app/views/smarter_listing/new.js.erb +2 -0
- data/app/views/smarter_listing/update.js.erb +1 -0
- data/lib/smarter_listing.rb +7 -0
- data/lib/smarter_listing/controller_extension.rb +77 -0
- data/lib/smarter_listing/engine.rb +4 -0
- data/lib/smarter_listing/helper.rb +92 -0
- data/lib/smarter_listing/loader.rb +25 -0
- data/lib/smarter_listing/version.rb +3 -0
- data/lib/tasks/smarter_listing_tasks.rake +4 -0
- data/test/controllers/listings_controller_test.rb +57 -0
- data/test/dummy/README.rdoc +28 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/stylesheets/application.css +15 -0
- data/test/dummy/app/controllers/application_controller.rb +5 -0
- data/test/dummy/app/controllers/listings_controller.rb +7 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/models/listing.rb +2 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/app/views/listings/_form.html.erb +8 -0
- data/test/dummy/app/views/listings/_listing.html.erb +5 -0
- data/test/dummy/app/views/listings/_table_header.html.erb +14 -0
- data/test/dummy/app/views/listings/index.html.erb +8 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +23 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +37 -0
- data/test/dummy/config/environments/production.rb +82 -0
- data/test/dummy/config/environments/test.rb +39 -0
- data/test/dummy/config/initializers/assets.rb +8 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +4 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/routes.rb +5 -0
- data/test/dummy/config/secrets.yml +22 -0
- data/test/dummy/db/development.sqlite3 +0 -0
- data/test/dummy/db/migrate/20140724101100_create_listings.rb +11 -0
- data/test/dummy/db/schema.rb +24 -0
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/log/development.log +16 -0
- data/test/dummy/log/test.log +21360 -0
- data/test/fixtures/listings.yml +4 -0
- data/test/helpers/smarter_listing_loader_test.rb +39 -0
- data/test/test_helper.rb +17 -0
- metadata +196 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: db91ff26a056d22121a2ef300d8c9d2efbd3fc2c
|
4
|
+
data.tar.gz: 0a28a1db18c045428979eec8c134ace962a99893
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: bfee046a907d192110fa45c9f9f6538b5394ba09119c287594f2a271b463fe80acf7d9dfd340bac8b432ea768d70cffffcd79e6d1ada354bd4606b01ee205908
|
7
|
+
data.tar.gz: 03fca7d00ecf4a9fd57b5046fe737aee26e22a9be37a0ebe5f31d78acff9c26f8ffd208d831e9c03bffe46a1218a92661af5d3e5fbde0f4a271ad26855ae7c60
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2014 YOURNAME
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
[](https://travis-ci.org/MichaelSp/smarter_listing)
|
2
|
+
|
3
|
+
SmarterListing
|
4
|
+
================
|
5
|
+
|
6
|
+
The [smart listing](http://showcase.sology.eu/smart_listing) from the guys at Sology is a real productivity boost.
|
7
|
+
But it's too verbose to include it into your rails app. This gem makes smart listing even smarter. It drys your controller out.
|
8
|
+
|
9
|
+
Usage
|
10
|
+
-----
|
11
|
+
|
12
|
+
* Gemfile
|
13
|
+
```ruby
|
14
|
+
gem 'smarter_listing'
|
15
|
+
```
|
16
|
+
then `bundle install`
|
17
|
+
|
18
|
+
* app/controllers/posts_controller.rb
|
19
|
+
```ruby
|
20
|
+
class PostController < ApplicationController
|
21
|
+
smarter_listing
|
22
|
+
|
23
|
+
# Look ma, no controller actions needs to be defined
|
24
|
+
|
25
|
+
private
|
26
|
+
def resource_params
|
27
|
+
params.require(:post).permit(:title, :body) if params[:post]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
```
|
31
|
+
|
32
|
+
* app/views/posts/_form.html.haml
|
33
|
+
```ruby
|
34
|
+
= bootstrap_form_for @post # this requires the fine gem 'bootstrap_form'. Check it out!
|
35
|
+
= f.text_field :title
|
36
|
+
= f.text_area :body
|
37
|
+
.pull-right
|
38
|
+
= f.primary
|
39
|
+
= link_to 'Cancel'. posts_path, class: 'btn btn-default'
|
40
|
+
```
|
41
|
+
|
42
|
+
* app/views/posts/_post.html.haml
|
43
|
+
```ruby
|
44
|
+
%td= object.title.truncate(30)
|
45
|
+
%td= object.body.truncate(80)
|
46
|
+
%td.actions= smart_listing_item_actions [action_copy(object,copy_post_path(object)),action_edit(object,edit_post_path(object)),action_destroy(object,post_path(object))]
|
47
|
+
```
|
48
|
+
|
49
|
+
* app/views/posts/_table_header.html.haml
|
50
|
+
```ruby
|
51
|
+
%table.table.table-striped
|
52
|
+
%tr
|
53
|
+
%th= smart_listing.sortable t("Created"), :created_at
|
54
|
+
%th= smart_listing.sortable t("Title"), :title
|
55
|
+
%th= smart_listing.sortable t("Body"), :body
|
56
|
+
%th
|
57
|
+
- smart_listing.collection.each do |post|
|
58
|
+
%tr.editable{data: {id: post.id}}
|
59
|
+
= smart_listing.render partial: 'posts/post', locals: {object: post}
|
60
|
+
|
61
|
+
= smart_listing.item_new colspan: 11, link: new_post_path
|
62
|
+
|
63
|
+
= smart_listing.paginate
|
64
|
+
= smart_listing.pagination_per_page_links
|
65
|
+
```
|
66
|
+
|
67
|
+
* app/views/posts/index.html.haml
|
68
|
+
```ruby
|
69
|
+
= smart_listing_controls_for(:posts, {class: "form-inline text-right"}) do
|
70
|
+
.form-group.filter.input-append
|
71
|
+
= text_field_tag :filter, '', class: "search form-control", placeholder: t("Search..."), autocomplete: :off
|
72
|
+
|
73
|
+
%button.btn.btn-primary.disabled{type: :submit}
|
74
|
+
=fa_icon 'search' # this requires gem 'font-awesome-rails'
|
75
|
+
=smart_listing_render(:posts)
|
76
|
+
|
77
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'SmarterListing'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.md')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
Bundler::GemHelper.install_tasks
|
21
|
+
|
22
|
+
require 'rake/testtask'
|
23
|
+
|
24
|
+
Rake::TestTask.new(:test) do |t|
|
25
|
+
t.libs << 'lib'
|
26
|
+
t.libs << 'test'
|
27
|
+
t.pattern = 'test/**/*_test.rb'
|
28
|
+
t.verbose = false
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
task default: :test
|
@@ -0,0 +1 @@
|
|
1
|
+
$('.select2').select2().removeClass('form-control');
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= smart_listing_item collection_sym, :create, resource, resource.valid? ? "#{current_engine}/#{collection_sym}/#{collection_action}" : "#{current_engine}/#{collection_sym}/form" %>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= smart_listing_update(collection_sym) %>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= smart_listing_item collection_sym, :update, resource, resource.valid? ? "#{current_engine}/#{collection_sym}/#{collection_action}" : "#{current_engine}/#{collection_sym}/form" %>
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module SmarterListing::ControllerExtension
|
2
|
+
|
3
|
+
def self.included base
|
4
|
+
base.helper_method :collection, :resource
|
5
|
+
base.include SmarterListing::Helper
|
6
|
+
base.class_eval do
|
7
|
+
# Actions
|
8
|
+
define_method :index do
|
9
|
+
collection
|
10
|
+
respond_to do |format|
|
11
|
+
format.html
|
12
|
+
format.js { render action: 'index.js.erb' }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
define_method :new do
|
17
|
+
instance_variable_get(resource_ivar) || instance_variable_set(resource_ivar, model.new(resource_params))
|
18
|
+
render 'smarter_listing/new'
|
19
|
+
end
|
20
|
+
|
21
|
+
define_method :create do
|
22
|
+
instance_variable_get(resource_ivar) || instance_variable_set(resource_ivar, model.create(resource_params))
|
23
|
+
render 'smarter_listing/create'
|
24
|
+
end
|
25
|
+
|
26
|
+
define_method :copy do
|
27
|
+
instance_variable_set resource_ivar, resource.dup
|
28
|
+
render 'smarter_listing/copy'
|
29
|
+
end
|
30
|
+
|
31
|
+
define_method :show do
|
32
|
+
resource
|
33
|
+
render resource, object: resource
|
34
|
+
end
|
35
|
+
|
36
|
+
define_method :edit do
|
37
|
+
resource
|
38
|
+
render 'smarter_listing/edit'
|
39
|
+
end
|
40
|
+
|
41
|
+
define_method :update do
|
42
|
+
resource.update resource_params
|
43
|
+
render 'smarter_listing/update'
|
44
|
+
end
|
45
|
+
|
46
|
+
define_method :destroy do
|
47
|
+
resource.destroy
|
48
|
+
render 'smarter_listing/destroy'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def filter_parameter
|
54
|
+
self.class.instance_variable_get :@filter_parameter
|
55
|
+
end
|
56
|
+
|
57
|
+
def filtered(model)
|
58
|
+
(!params[filter_parameter].blank?) ? model.search { fulltext "#{params[filter_parameter]}" }.results : model.all
|
59
|
+
end
|
60
|
+
|
61
|
+
def load_collection
|
62
|
+
instance_variable_set collection_ivar, smart_listing_create(collection_sym, filtered(model), partial: "#{current_engine}/#{collection_sym}/table_header")
|
63
|
+
end
|
64
|
+
|
65
|
+
def load_resource
|
66
|
+
instance_variable_set resource_ivar, (model.find(params[:id]) rescue (action_name == 'new' ? model.new(resource_params) : nil))
|
67
|
+
end
|
68
|
+
|
69
|
+
def resource
|
70
|
+
instance_variable_get(resource_ivar) || load_resource
|
71
|
+
end
|
72
|
+
|
73
|
+
def collection
|
74
|
+
instance_variable_get(collection_ivar) || load_collection
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module SmarterListing
|
2
|
+
module Helper
|
3
|
+
|
4
|
+
# def self.included base
|
5
|
+
# base.helper_method :collection_sym, :collection_action, :collection_ivar, :resource_sym, :resource_ivar, :model
|
6
|
+
# base.helper_method :action_copy, :action_edit, :action_destroy, :current_engine
|
7
|
+
# end
|
8
|
+
|
9
|
+
def collection_sym
|
10
|
+
@collection_sym = nil
|
11
|
+
@collection_sym ||= model.to_s.underscore.downcase.pluralize.to_sym
|
12
|
+
end
|
13
|
+
|
14
|
+
def collection_action
|
15
|
+
@collection_action = nil
|
16
|
+
@collection_action ||= model.to_s.underscore.downcase.singularize.to_sym
|
17
|
+
end
|
18
|
+
|
19
|
+
def collection_ivar
|
20
|
+
"@#{collection_sym}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def resource_sym
|
24
|
+
@resource_sym ||= model.to_s.underscore.downcase.to_sym
|
25
|
+
end
|
26
|
+
|
27
|
+
def resource_ivar
|
28
|
+
"@#{resource_sym}"
|
29
|
+
end
|
30
|
+
|
31
|
+
def current_engine
|
32
|
+
self.class.parent == Object ? '' : self.class.parent.to_s.downcase
|
33
|
+
end
|
34
|
+
|
35
|
+
def model
|
36
|
+
@model = nil
|
37
|
+
@model ||= begin
|
38
|
+
# First priority is the namespaced model, e.g. User::Group
|
39
|
+
resource_class ||= begin
|
40
|
+
namespaced_class = self.name.sub(/Controller/, '').singularize
|
41
|
+
namespaced_class.constantize
|
42
|
+
rescue NameError
|
43
|
+
nil
|
44
|
+
end
|
45
|
+
|
46
|
+
# Second priority is the top namespace model, e.g. EngineName::Article for EngineName::Admin::ArticlesController
|
47
|
+
resource_class ||= begin
|
48
|
+
namespaced_classes = self.name.sub(/Controller/, '').split('::')
|
49
|
+
namespaced_class = [namespaced_classes.first, namespaced_classes.last].join('::').singularize
|
50
|
+
namespaced_class.constantize
|
51
|
+
rescue NameError
|
52
|
+
nil
|
53
|
+
end
|
54
|
+
|
55
|
+
# Third priority the camelcased c, i.e. UserGroup
|
56
|
+
resource_class ||= begin
|
57
|
+
camelcased_class = self.name.sub(/Controller/, '').gsub('::', '').singularize
|
58
|
+
camelcased_class.constantize
|
59
|
+
rescue NameError
|
60
|
+
nil
|
61
|
+
end
|
62
|
+
|
63
|
+
# Otherwise use the Group class, or fail
|
64
|
+
resource_class ||= begin
|
65
|
+
class_name = self.controller_name.classify
|
66
|
+
class_name.constantize
|
67
|
+
rescue NameError => e
|
68
|
+
raise unless e.message.include?(class_name)
|
69
|
+
nil
|
70
|
+
end
|
71
|
+
resource_class
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def action_copy(object, path)
|
76
|
+
{
|
77
|
+
name: :copy,
|
78
|
+
custom_url: path,
|
79
|
+
custom_icon: SmartListing.config.classes(:icon_copy),
|
80
|
+
custom_title: 'Copy'
|
81
|
+
}
|
82
|
+
end
|
83
|
+
|
84
|
+
def action_edit(object, path)
|
85
|
+
{name: :edit, url: path}
|
86
|
+
end
|
87
|
+
|
88
|
+
def action_destroy(object, path)
|
89
|
+
{name: :destroy, url: path}
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'smart_listing'
|
2
|
+
require 'kaminari'
|
3
|
+
|
4
|
+
module SmarterListing
|
5
|
+
module Loader
|
6
|
+
def initialize
|
7
|
+
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.extended base
|
11
|
+
def smarter_listing(filter_parameter = :filter)
|
12
|
+
helper SmartListing::Helper
|
13
|
+
include SmartListing::Helper::ControllerExtensions
|
14
|
+
|
15
|
+
helper SmarterListing::Helper
|
16
|
+
include SmarterListing::ControllerExtension
|
17
|
+
|
18
|
+
instance_variable_set :@filter_parameter, filter_parameter
|
19
|
+
prepend Loader
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
ActionController::Base.extend SmarterListing::Loader
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
require 'smarter_listing'
|
4
|
+
|
5
|
+
class ListingsControllerTest < ActionController::TestCase
|
6
|
+
setup do
|
7
|
+
@listing = listings(:one)
|
8
|
+
ListingsController.smarter_listing
|
9
|
+
end
|
10
|
+
|
11
|
+
test 'should have the methods from all helpers' do
|
12
|
+
assert_includes @controller.methods, :create
|
13
|
+
assert_includes @controller.methods, :show
|
14
|
+
assert_includes @controller.methods, :update
|
15
|
+
assert_includes @controller.methods, :destroy
|
16
|
+
assert_includes @controller.methods, :new
|
17
|
+
end
|
18
|
+
|
19
|
+
test "should get index" do
|
20
|
+
get :index
|
21
|
+
assert_response :success
|
22
|
+
assert_not_nil assigns(:listings)
|
23
|
+
end
|
24
|
+
|
25
|
+
test "should get new" do
|
26
|
+
xhr :get, :new, format: :js
|
27
|
+
assert_response :success
|
28
|
+
end
|
29
|
+
|
30
|
+
test "should create listing" do
|
31
|
+
assert_difference('Listing.count') do
|
32
|
+
resource_params = {content: @listing.content, deleted_at: @listing.deleted_at, name: 'newName'}
|
33
|
+
xhr :post, :create, listing: resource_params, format: :js
|
34
|
+
assert_empty @listing.errors
|
35
|
+
end
|
36
|
+
assert_response :success
|
37
|
+
end
|
38
|
+
|
39
|
+
test "should get edit" do
|
40
|
+
xhr :get, :edit, id: @listing, format: :js
|
41
|
+
assert_response :success
|
42
|
+
end
|
43
|
+
|
44
|
+
test "should update listing" do
|
45
|
+
resource_params = {content: @listing.content, deleted_at: @listing.deleted_at, name: 'newName'}
|
46
|
+
xhr :patch, :update, id: @listing, listing: resource_params, format: :js
|
47
|
+
assert_empty @listing.errors
|
48
|
+
assert_response :success
|
49
|
+
end
|
50
|
+
|
51
|
+
test "should destroy listing" do
|
52
|
+
assert_difference('Listing.count', -1) do
|
53
|
+
xhr :delete, :destroy, id: @listing, format: :js
|
54
|
+
end
|
55
|
+
assert_response :success
|
56
|
+
end
|
57
|
+
end
|