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 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