smarter_listing 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Build Status](https://travis-ci.org/MichaelSp/smarter_listing.svg?branch=master)](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
|