simple_admin 0.1.0 → 0.2.1

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.
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
+
@@ -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 :title => 'Intersting post stats' do
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 lookup_resource
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
- col.data.call(@resource, col)
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 = collection.to_a if collection.is_a?(Hash)
91
- collection.map { |o| [pretty_format(o), o.id] }
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 = klass.send(input_name) || []
102
- checkboxes = template.content_tag :div, :class => "check_boxes_wrapper" do
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
- @interface.sidebars_for(:index).each do |sidebar|
5
- instance_exec(sidebar, &sidebar[:data])
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].call(@resource)
15
+ instance_exec(@resource, &options[:title])
16
16
  when Symbol
17
17
  if @resource
18
18
  @resource.send(optons[:title])
@@ -8,7 +8,7 @@
8
8
  @collection.each do |object|
9
9
  csv << cols.map do |col|
10
10
  if col.data
11
- col.data.call(object, col)
11
+ instance_exec(object, &col.data)
12
12
  else
13
13
  pretty_format(object.send(col.attribute))
14
14
  end
@@ -36,7 +36,7 @@
36
36
  <% @interface.attributes_for(:index).each do |col| %>
37
37
  <td>
38
38
  <% if col.data %>
39
- <%= col.data.call(object, col) %>
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" />
@@ -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| require 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|
@@ -31,5 +31,8 @@ module SimpleAdmin
31
31
  @interface.before << options
32
32
  end
33
33
 
34
+ # Comfort the masses
35
+ alias_method :before_filter, :before
36
+
34
37
  end
35
38
  end
@@ -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.downcase.to_sym
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
- section(sym).options[:filters].attributes
25
+ options_for(sym)[:filters].attributes
26
26
  end
27
27
 
28
28
  def attributes_for(sym)
29
- section(sym).options[:attributes].attributes
29
+ options_for(sym)[:attributes].attributes
30
30
  end
31
31
 
32
32
  def sidebars_for(sym)
33
- section(sym).options[:sidebars] || []
33
+ options_for(sym)[:sidebars] || []
34
34
  end
35
35
 
36
36
  def options_for(sym)
37
- section(sym).options
37
+ sym = :form if [:new, :edit].include?(sym)
38
+ section(sym).options || {}
38
39
  end
39
40
 
40
41
  def actions
@@ -1,3 +1,3 @@
1
1
  module SimpleAdmin
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.1"
3
3
  end
@@ -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 {|sidebar| SimpleAdmin.success if sidebar[:title] == 'Awes!' }
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: 27
4
+ hash: 21
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
+ - 2
8
9
  - 1
9
- - 0
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-21 00:00:00 -07:00
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