simple_admin 0.1.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +56 -0
- data/README.rdoc +8 -2
- data/app/controllers/simple_admin/admin_controller.rb +7 -8
- data/app/helpers/simple_admin/display_helper.rb +1 -1
- data/app/helpers/simple_admin/filter_helper.rb +24 -10
- data/app/helpers/simple_admin/sidebar_helper.rb +4 -2
- data/app/helpers/simple_admin/title_helper.rb +1 -1
- data/app/views/simple_admin/admin/index.csv.erb +1 -1
- data/app/views/simple_admin/admin/index.html.erb +2 -2
- data/lib/simple_admin.rb +13 -1
- data/lib/simple_admin/builder.rb +3 -0
- data/lib/simple_admin/engine.rb +12 -0
- data/lib/simple_admin/interface.rb +6 -5
- data/lib/simple_admin/version.rb +1 -1
- data/lib/tasks/routes.rake +31 -0
- data/spec/controllers/simple_admin/admin_controller_spec.rb +1 -1
- data/spec/simple_admin/interface_spec.rb +8 -0
- metadata +6 -4
data/LICENSE
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
MIT LICENSE
|
2
|
+
|
3
|
+
Copyright (c) 2011 Jeff Rafter
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
23
|
+
|
24
|
+
|
25
|
+
Some of the code contained in this project is subject to additional
|
26
|
+
Copyright and license:
|
27
|
+
|
28
|
+
Original license from ActiveAdmin, Greg Bell
|
29
|
+
--------------------------------------------
|
30
|
+
|
31
|
+
Copyright (c) 2010 Greg Bell, VersaPay Corporation
|
32
|
+
|
33
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
34
|
+
a copy of this software and associated documentation files (the
|
35
|
+
"Software"), to deal in the Software without restriction, including
|
36
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
37
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
38
|
+
permit persons to whom the Software is furnished to do so, subject to
|
39
|
+
the following conditions:
|
40
|
+
|
41
|
+
The above copyright notice and this permission notice shall be
|
42
|
+
included in all copies or substantial portions of the Software.
|
43
|
+
|
44
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
45
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
46
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
47
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
48
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
49
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
50
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
51
|
+
|
52
|
+
Iconic Icons are designed by P.J. Onori and are shared under
|
53
|
+
the Creative Commons Attribution-Share Alike 3.0 license:
|
54
|
+
http://creativecommons.org/licenses/by-sa/3.0/us
|
55
|
+
http://somerandomdude.com/projects/iconic/
|
56
|
+
|
data/README.rdoc
CHANGED
@@ -19,7 +19,8 @@ set of features.
|
|
19
19
|
|
20
20
|
== Getting started
|
21
21
|
|
22
|
-
In your Gemfile, include simple_admin and formtastic
|
22
|
+
In your Gemfile, include simple_admin and formtastic (and fastercsv
|
23
|
+
if you are on an older version of Ruby):
|
23
24
|
|
24
25
|
gem "simple_admin"
|
25
26
|
gem "formtastic"
|
@@ -184,7 +185,7 @@ of rendering:
|
|
184
185
|
|
185
186
|
SimpleAdmin.register :post do
|
186
187
|
index do
|
187
|
-
sidebar
|
188
|
+
sidebar do
|
188
189
|
# Within index you have @collection, in other views you have @resource
|
189
190
|
your_post_stats_helper(@collection)
|
190
191
|
end
|
@@ -217,6 +218,11 @@ generated at initialization. Available actions are:
|
|
217
218
|
* create
|
218
219
|
* update
|
219
220
|
|
221
|
+
You can also see the routes that are generated by your admin interfaces
|
222
|
+
by running:
|
223
|
+
|
224
|
+
rake routes:simple_admin
|
225
|
+
|
220
226
|
== Configuration options
|
221
227
|
|
222
228
|
All of the configuration for SimpleAdmin happens within the
|
@@ -5,8 +5,8 @@ module SimpleAdmin
|
|
5
5
|
class AdminController < ::ApplicationController
|
6
6
|
before_filter :require_user
|
7
7
|
before_filter :lookup_interface
|
8
|
+
before_filter :lookup_before
|
8
9
|
before_filter :lookup_resource, :only => [:show, :edit, :update, :destroy]
|
9
|
-
before_filter :handle_before
|
10
10
|
|
11
11
|
unloadable
|
12
12
|
|
@@ -25,7 +25,6 @@ module SimpleAdmin
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def show
|
28
|
-
@resource = @interface.constant.find(params[:id])
|
29
28
|
respond_with(@resource)
|
30
29
|
end
|
31
30
|
|
@@ -93,23 +92,23 @@ module SimpleAdmin
|
|
93
92
|
raise UnknownAdminInterface.new("Could not find the interface for simple admin") unless @interface
|
94
93
|
end
|
95
94
|
|
96
|
-
def
|
97
|
-
@resource = @interface.constant.find(params[:id])
|
98
|
-
end
|
99
|
-
|
100
|
-
def handle_before
|
95
|
+
def lookup_before
|
101
96
|
@interface.before.each do |before|
|
102
97
|
next unless before[:actions].include?(params[:action].to_sym)
|
103
98
|
instance_eval(&before[:data])
|
104
99
|
end
|
105
100
|
end
|
106
101
|
|
102
|
+
def lookup_resource
|
103
|
+
@resource ||= @interface.constant.find(params[:id])
|
104
|
+
end
|
105
|
+
|
107
106
|
def clean_search_params(search_params)
|
108
107
|
return {} unless search_params.is_a?(Hash)
|
109
108
|
search_params = search_params.dup
|
110
109
|
search_params.delete_if do |key, value|
|
111
110
|
value == "" ||
|
112
|
-
["utf8", "scope", "commit", "action", "order", "interface", "controller", "format"].include?(key)
|
111
|
+
["utf8", "scope", "commit", "action", "order", "interface", "controller", "format", "page"].include?(key)
|
113
112
|
end
|
114
113
|
search_params
|
115
114
|
end
|
@@ -26,7 +26,7 @@ module SimpleAdmin
|
|
26
26
|
|
27
27
|
def data_for(col)
|
28
28
|
value = if col.data
|
29
|
-
|
29
|
+
instance_exec(@resource, &col.data)
|
30
30
|
elsif col.attribute.to_s =~ /^([\w]+)_id$/ && @resource.respond_to?($1.to_sym)
|
31
31
|
pretty_format(@resource.send($1))
|
32
32
|
else
|
@@ -68,38 +68,52 @@ module SimpleAdmin
|
|
68
68
|
else
|
69
69
|
association_name
|
70
70
|
end
|
71
|
-
input_name = (input_name + "_eq").to_sym
|
71
|
+
input_name = (input_name.to_s + "_eq").to_sym
|
72
72
|
collection = find_collection_for_column(klass, association_name, options)
|
73
73
|
[ label(input_name, method.to_s.titlecase),
|
74
74
|
select_tag(input_name, options_for_select(collection, params[input_name]), :include_blank => options[:include_blank] || 'Any')
|
75
75
|
].join("\n").html_safe
|
76
76
|
end
|
77
77
|
|
78
|
+
def generate_association_input_name(klass, method) #:nodoc:
|
79
|
+
if reflection = reflection_for(klass, method)
|
80
|
+
if [:has_and_belongs_to_many, :has_many].include?(reflection.macro)
|
81
|
+
"#{method.to_s.singularize}_ids"
|
82
|
+
else
|
83
|
+
reflection.options[:foreign_key] || "#{method}_id"
|
84
|
+
end
|
85
|
+
else
|
86
|
+
method
|
87
|
+
end.to_sym
|
88
|
+
end
|
89
|
+
|
78
90
|
def find_collection_for_column(klass, column, options) #:nodoc:
|
79
91
|
collection = if options[:collection]
|
80
|
-
options.delete(:collection)
|
92
|
+
collection = options.delete(:collection)
|
93
|
+
collection = collection.to_a if collection.is_a?(Hash)
|
94
|
+
collection.map { |o| [pretty_format(o.first), o.last] }
|
81
95
|
elsif reflection = reflection_for(klass, column)
|
82
96
|
options[:find_options] ||= {}
|
83
97
|
if conditions = reflection.options[:conditions]
|
84
98
|
options[:find_options][:conditions] = reflection.klass.merge_conditions(conditions, options[:find_options][:conditions])
|
85
99
|
end
|
86
|
-
reflection.klass.find(:all, options[:find_options])
|
100
|
+
collection = reflection.klass.find(:all, options[:find_options])
|
101
|
+
collection.map { |o| [pretty_format(o), o.id] }
|
87
102
|
else
|
88
103
|
boolean_collection(klass, column, options)
|
89
104
|
end
|
90
|
-
collection
|
91
|
-
|
92
|
-
end
|
105
|
+
collection
|
106
|
+
end
|
93
107
|
|
94
108
|
def boolean_collection(klass, column, options)
|
95
109
|
[['Yes', true], ['No', false]]
|
96
110
|
end
|
97
111
|
|
98
112
|
def filter_check_boxes_input(klass, method, options = {})
|
99
|
-
input_name = (generate_association_input_name(method).to_s + "_in").to_sym
|
100
|
-
collection = find_collection_for_column(method, options)
|
101
|
-
selected_values =
|
102
|
-
checkboxes =
|
113
|
+
input_name = (generate_association_input_name(klass, method).to_s + "_in").to_sym
|
114
|
+
collection = find_collection_for_column(klass, method, options)
|
115
|
+
selected_values = params[input_name] || []
|
116
|
+
checkboxes = content_tag :div, :class => "check_boxes_wrapper" do
|
103
117
|
collection.map do |c|
|
104
118
|
label = c.is_a?(Array) ? c.first : c
|
105
119
|
value = c.is_a?(Array) ? c.last : c
|
@@ -1,9 +1,11 @@
|
|
1
1
|
module SimpleAdmin
|
2
2
|
module SidebarHelper
|
3
3
|
def sidebars
|
4
|
-
|
5
|
-
|
4
|
+
content = "".html_safe
|
5
|
+
@interface.sidebars_for(params[:action].to_sym).each do |sidebar|
|
6
|
+
content << instance_eval(&sidebar[:data])
|
6
7
|
end
|
8
|
+
content
|
7
9
|
end
|
8
10
|
end
|
9
11
|
end
|
@@ -12,7 +12,7 @@ module SimpleAdmin
|
|
12
12
|
options = @interface.options_for(params[:action].to_sym)
|
13
13
|
case options[:title]
|
14
14
|
when Proc
|
15
|
-
options[:title]
|
15
|
+
instance_exec(@resource, &options[:title])
|
16
16
|
when Symbol
|
17
17
|
if @resource
|
18
18
|
@resource.send(optons[:title])
|
@@ -36,7 +36,7 @@
|
|
36
36
|
<% @interface.attributes_for(:index).each do |col| %>
|
37
37
|
<td>
|
38
38
|
<% if col.data %>
|
39
|
-
<%=
|
39
|
+
<%= instance_exec(object, &col.data) %>
|
40
40
|
<% else %>
|
41
41
|
<%= pretty_format(object.send(col.attribute)) %>
|
42
42
|
<% end %>
|
@@ -66,7 +66,7 @@
|
|
66
66
|
<div class="panel_contents">
|
67
67
|
<%= form_tag '', :class => "q_search", :id => "q_search", :method => "get" do %>
|
68
68
|
<% @interface.filters_for(:index).each do |col| %>
|
69
|
-
<%= filter_for(col.attribute, @interface.constant) %>
|
69
|
+
<%= filter_for(col.attribute, @interface.constant, col.options) %>
|
70
70
|
<% end %>
|
71
71
|
<div class="buttons">
|
72
72
|
<input name="commit" type="submit" value="Filter" />
|
data/lib/simple_admin.rb
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
module SimpleAdmin
|
2
2
|
require 'simple_admin/engine' if defined?(Rails) && Rails::VERSION::MAJOR == 3
|
3
|
+
require 'simple_admin/interface'
|
4
|
+
require 'simple_admin/builder'
|
5
|
+
require 'simple_admin/section'
|
6
|
+
require 'simple_admin/attributes'
|
7
|
+
require 'simple_admin/filters'
|
8
|
+
require 'simple_admin/breadcrumbs'
|
9
|
+
|
3
10
|
|
4
11
|
mattr_accessor :require_user_method,
|
5
12
|
:current_user_method,
|
@@ -36,7 +43,7 @@ module SimpleAdmin
|
|
36
43
|
@@registered = []
|
37
44
|
# We load up all of the admin files on launch, if they change you need to restart
|
38
45
|
begin
|
39
|
-
Dir[Rails.root.join("app/admin/**/*.rb")].each {|f|
|
46
|
+
Dir[Rails.root.join("app/admin/**/*.rb")].each {|f| load f}
|
40
47
|
rescue LoadError => e
|
41
48
|
# For certain kinds of load errors, we want to give a more helpful message
|
42
49
|
if e.message.match(/Expected .* to define .*/)
|
@@ -49,6 +56,11 @@ module SimpleAdmin
|
|
49
56
|
@@registered
|
50
57
|
end
|
51
58
|
|
59
|
+
# Clear the routes and registered interfaces
|
60
|
+
def unregister
|
61
|
+
@@registered = nil
|
62
|
+
end
|
63
|
+
|
52
64
|
# Called by the initializer
|
53
65
|
#
|
54
66
|
# SimpleAdmin.setup do |config|
|
data/lib/simple_admin/builder.rb
CHANGED
data/lib/simple_admin/engine.rb
CHANGED
@@ -4,5 +4,17 @@ require 'rails'
|
|
4
4
|
module SimpleAdmin
|
5
5
|
class Engine < Rails::Engine
|
6
6
|
isolate_namespace SimpleAdmin
|
7
|
+
initializer 'simple_admin' do
|
8
|
+
if Rails.env == "development"
|
9
|
+
simple_admin_reloader = ActiveSupport::FileUpdateChecker.new(Dir["app/admin/**/*"], true) do
|
10
|
+
SimpleAdmin.unregister
|
11
|
+
Rails.application.reload_routes!
|
12
|
+
end
|
13
|
+
|
14
|
+
ActionDispatch::Callbacks.to_prepare do
|
15
|
+
simple_admin_reloader.execute_if_updated
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
7
19
|
end
|
8
20
|
end
|
@@ -7,7 +7,7 @@ module SimpleAdmin
|
|
7
7
|
def initialize(resource, options={}, &block)
|
8
8
|
if resource.is_a?(Class)
|
9
9
|
@constant = resource
|
10
|
-
@symbol = resource.name.
|
10
|
+
@symbol = resource.name.underscore.to_sym
|
11
11
|
else
|
12
12
|
@constant = resource.to_s.camelize.singularize.constantize
|
13
13
|
@symbol = resource.to_sym
|
@@ -22,19 +22,20 @@ module SimpleAdmin
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def filters_for(sym)
|
25
|
-
|
25
|
+
options_for(sym)[:filters].attributes
|
26
26
|
end
|
27
27
|
|
28
28
|
def attributes_for(sym)
|
29
|
-
|
29
|
+
options_for(sym)[:attributes].attributes
|
30
30
|
end
|
31
31
|
|
32
32
|
def sidebars_for(sym)
|
33
|
-
|
33
|
+
options_for(sym)[:sidebars] || []
|
34
34
|
end
|
35
35
|
|
36
36
|
def options_for(sym)
|
37
|
-
|
37
|
+
sym = :form if [:new, :edit].include?(sym)
|
38
|
+
section(sym).options || {}
|
38
39
|
end
|
39
40
|
|
40
41
|
def actions
|
data/lib/simple_admin/version.rb
CHANGED
@@ -0,0 +1,31 @@
|
|
1
|
+
# Based on the routes.rake tasks from Rails
|
2
|
+
namespace :routes do
|
3
|
+
desc 'Print out all defined routes in match order, with names. Target specific controller with CONTROLLER=x.'
|
4
|
+
task :simple_admin => :environment do
|
5
|
+
all_routes = SimpleAdmin::Engine.routes.routes
|
6
|
+
|
7
|
+
if ENV['CONTROLLER']
|
8
|
+
all_routes = all_routes.select{ |route| route.defaults[:controller] == ENV['CONTROLLER'] }
|
9
|
+
end
|
10
|
+
|
11
|
+
routes = all_routes.collect do |route|
|
12
|
+
|
13
|
+
reqs = route.requirements.dup
|
14
|
+
reqs[:to] = route.app unless route.app.class.name.to_s =~ /^ActionDispatch::Routing/
|
15
|
+
reqs = reqs.empty? ? "" : reqs.inspect
|
16
|
+
|
17
|
+
{:name => route.name.to_s, :verb => route.verb.to_s, :path => route.path, :reqs => reqs}
|
18
|
+
end
|
19
|
+
|
20
|
+
# Skip the route if it's internal info route
|
21
|
+
routes.reject! { |r| r[:path] =~ %r{/rails/info/properties|^/assets} }
|
22
|
+
|
23
|
+
name_width = routes.map{ |r| r[:name].length }.max
|
24
|
+
verb_width = routes.map{ |r| r[:verb].length }.max
|
25
|
+
path_width = routes.map{ |r| r[:path].length }.max
|
26
|
+
|
27
|
+
routes.each do |r|
|
28
|
+
puts "#{r[:name].rjust(name_width)} #{r[:verb].ljust(verb_width)} #{r[:path].ljust(path_width)} #{r[:reqs]}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -14,7 +14,7 @@ describe SimpleAdmin::AdminController do
|
|
14
14
|
|
15
15
|
it "should render the sidebars" do
|
16
16
|
SimpleAdmin.expects(:success)
|
17
|
-
@block = Proc.new {
|
17
|
+
@block = Proc.new { SimpleAdmin.success }
|
18
18
|
@sidebar = {:title => 'Awes!', :data => @block}
|
19
19
|
SimpleAdmin::Interface.any_instance.expects(:sidebars_for).with(:index).returns([@sidebar])
|
20
20
|
get :index, :interface => "things"
|
@@ -1,11 +1,19 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
+
class ThingWithCrazyClassName < Thing; end
|
4
|
+
|
3
5
|
describe SimpleAdmin::Interface do
|
4
6
|
it "accepts a constant as the resource" do
|
5
7
|
@interface = SimpleAdmin.register(Thing)
|
6
8
|
@interface.constant.should == Thing
|
7
9
|
end
|
8
10
|
|
11
|
+
it "accepts a crazy constant as the resource" do
|
12
|
+
@interface = SimpleAdmin.register(ThingWithCrazyClassName)
|
13
|
+
@interface.constant.should == ThingWithCrazyClassName
|
14
|
+
@interface.member.should == "thing_with_crazy_class_name"
|
15
|
+
end
|
16
|
+
|
9
17
|
it "accepts a symbol as the resource" do
|
10
18
|
@interface = SimpleAdmin.register(:thing)
|
11
19
|
@interface.constant.should == Thing
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: simple_admin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 21
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
+
- 2
|
8
9
|
- 1
|
9
|
-
|
10
|
-
version: 0.1.0
|
10
|
+
version: 0.2.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Jeff Rafter
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-06-
|
18
|
+
date: 2011-06-22 00:00:00 -07:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -184,6 +184,7 @@ files:
|
|
184
184
|
- .gitignore
|
185
185
|
- .rspec
|
186
186
|
- Gemfile
|
187
|
+
- LICENSE
|
187
188
|
- README.rdoc
|
188
189
|
- Rakefile
|
189
190
|
- TODO.rdoc
|
@@ -222,6 +223,7 @@ files:
|
|
222
223
|
- lib/simple_admin/interface.rb
|
223
224
|
- lib/simple_admin/section.rb
|
224
225
|
- lib/simple_admin/version.rb
|
226
|
+
- lib/tasks/routes.rake
|
225
227
|
- rails/init.rb
|
226
228
|
- simple_admin.gemspec
|
227
229
|
- spec/acceptance/admin_thing_spec.rb
|