merb-admin 0.6.2 → 0.6.3

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/README.rdoc CHANGED
@@ -11,7 +11,7 @@ http://github.com/sferik/merb-admin/raw/master/screenshots/edit.png
11
11
  == Installation
12
12
  $ gem install merb-admin -s http://gemcutter.org
13
13
  In your app, add the following dependency to <tt>config/dependencies.rb</tt>:
14
- dependency "merb-admin", "0.6.2"
14
+ dependency "merb-admin", "0.6.3"
15
15
  Add the following route to <tt>config/router.rb</tt>:
16
16
  add_slice(:merb_admin, :path_prefix => "admin")
17
17
  Then, run the following rake task:
@@ -37,6 +37,7 @@ There are many ways to contribute:
37
37
  * by writing documentation
38
38
  * by writing specifications
39
39
  * by writing code (no patch is too small: fix typos in comments or inconsistent whitespace)
40
+ * by refactoring code
40
41
  * by reviewing patches
41
42
  * financially[http://pledgie.com/campaigns/5428]
42
43
 
data/Rakefile CHANGED
@@ -9,8 +9,8 @@ AUTHOR = "Erik Michaels-Ober"
9
9
  EMAIL = "sferik@gmail.com"
10
10
  HOMEPAGE = "http://github.com/sferik/merb-admin"
11
11
  SUMMARY = "MerbAdmin is a Merb plugin that provides an easy-to-use interface for managing your data."
12
- GEM_VERSION = "0.6.2"
13
- MERB_GEM_VERSION = "1.0.12"
12
+ GEM_VERSION = "0.6.3"
13
+ MERB_GEM_VERSION = "1.0.15"
14
14
 
15
15
  spec = Gem::Specification.new do |s|
16
16
  s.rubyforge_project = "merb"
@@ -3,9 +3,10 @@ require File.join( File.dirname(__FILE__), '..', '..', 'lib', 'abstract_model' )
3
3
  class MerbAdmin::Main < MerbAdmin::Application
4
4
  include Merb::MerbAdmin::MainHelper
5
5
 
6
- before :find_models, :only => ['index']
7
- before :find_model, :exclude => ['index']
8
- before :find_object, :only => ['edit', 'update', 'delete', 'destroy']
6
+ before :get_models, :only => ['index']
7
+ before :get_model, :exclude => ['index']
8
+ before :get_object, :only => ['edit', 'update', 'delete', 'destroy']
9
+ before :get_attributes, :only => ['create', 'update']
9
10
 
10
11
  def index
11
12
  render(:layout => 'dashboard')
@@ -13,29 +14,25 @@ class MerbAdmin::Main < MerbAdmin::Application
13
14
 
14
15
  def list
15
16
  options = {}
16
- merge_query!(options)
17
- merge_filter!(options)
18
- merge_sort!(options)
19
- merge_sort_reverse!(options)
20
-
17
+ options.merge!(sort)
18
+ options.merge!(sort_reverse)
19
+ options.merge!(query(options))
20
+ options.merge!(filter(options))
21
+ # merge_query!(options)
22
+ # merge_filter!(options)
23
+ per_page = MerbAdmin[:per_page]
21
24
  if params[:all]
22
- options = {
23
- :limit => MerbAdmin[:per_page] * 2,
24
- }.merge(options)
25
+ options.merge!(:limit => per_page * 2)
25
26
  @objects = @abstract_model.all(options).reverse
26
27
  else
27
28
  @current_page = (params[:page] || 1).to_i
28
- options = {
29
- :page => @current_page,
30
- :per_page => MerbAdmin[:per_page],
31
- }.merge(options)
29
+ options.merge!(:page => @current_page, :per_page => per_page)
32
30
  @page_count, @objects = @abstract_model.paginated(options)
33
31
  options.delete(:page)
34
32
  options.delete(:per_page)
35
33
  options.delete(:offset)
36
34
  options.delete(:limit)
37
35
  end
38
-
39
36
  @record_count = @abstract_model.count(options)
40
37
  render(:layout => 'list')
41
38
  end
@@ -50,47 +47,19 @@ class MerbAdmin::Main < MerbAdmin::Application
50
47
  end
51
48
 
52
49
  def create
53
- object = params[@abstract_model.singular_name] || {}
54
- # Delete fields that are blank
55
- object.each do |key, value|
56
- object[key] = nil if value.blank?
57
- end
58
- has_one_associations = @abstract_model.has_one_associations.map{|association| [association, (params[:associations] || {}).delete(association[:name])]}
59
- has_many_associations = @abstract_model.has_many_associations.map{|association| [association, (params[:associations] || {}).delete(association[:name])]}
60
- @object = @abstract_model.new(object)
61
- if @object.save && has_one_associations.each{|association, id| update_association(association, id)} && has_many_associations.each{|association, ids| update_associations(association, ids.to_a)}
62
- if params[:_continue]
63
- redirect(url(:merb_admin_edit, :model_name => @abstract_model.singular_name, :id => @object.id), :message => {:notice => "#{@abstract_model.pretty_name} was successfully created"})
64
- elsif params[:_add_another]
65
- redirect(url(:merb_admin_new, :model_name => @abstract_model.singular_name), :message => {:notice => "#{@abstract_model.pretty_name} was successfully created"})
66
- else
67
- redirect(url(:merb_admin_list, :model_name => @abstract_model.singular_name), :message => {:notice => "#{@abstract_model.pretty_name} was successfully created"})
68
- end
50
+ @object = @abstract_model.new(@attributes)
51
+ if @object.save && update_all_associations
52
+ redirect_on_success
69
53
  else
70
- message[:error] = "#{@abstract_model.pretty_name} failed to be created"
71
- render(:new, :layout => 'form')
54
+ render_error
72
55
  end
73
56
  end
74
57
 
75
58
  def update
76
- object = params[@abstract_model.singular_name] || {}
77
- # Delete fields that are blank
78
- object.each do |key, value|
79
- object[key] = nil if value.blank?
80
- end
81
- has_one_associations = @abstract_model.has_one_associations.map{|association| [association, (params[:associations] || {}).delete(association[:name])]}
82
- has_many_associations = @abstract_model.has_many_associations.map{|association| [association, (params[:associations] || {}).delete(association[:name])]}
83
- if @object.update_attributes(object) && has_one_associations.each{|association, id| update_association(association, id)} && has_many_associations.each{|association, ids| update_associations(association, ids.to_a)}
84
- if params[:_continue]
85
- redirect(url(:merb_admin_edit, :model_name => @abstract_model.singular_name, :id => @object.id), :message => {:notice => "#{@abstract_model.pretty_name} was successfully updated"})
86
- elsif params[:_add_another]
87
- redirect(url(:merb_admin_new, :model_name => @abstract_model.singular_name), :message => {:notice => "#{@abstract_model.pretty_name} was successfully updated"})
88
- else
89
- redirect(url(:merb_admin_list, :model_name => @abstract_model.singular_name), :message => {:notice => "#{@abstract_model.pretty_name} was successfully updated"})
90
- end
59
+ if @object.update_attributes(@attributes) && update_all_associations
60
+ redirect_on_success
91
61
  else
92
- message[:error] = "#{@abstract_model.pretty_name} failed to be updated"
93
- render(:edit, :layout => 'form')
62
+ render_error
94
63
  end
95
64
  end
96
65
 
@@ -108,70 +77,91 @@ class MerbAdmin::Main < MerbAdmin::Application
108
77
 
109
78
  private
110
79
 
111
- def find_models
80
+ def get_models
112
81
  @abstract_models = MerbAdmin::AbstractModel.all
113
82
  end
114
83
 
115
- def find_model
84
+ def get_model
116
85
  model_name = params[:model_name].camel_case
117
86
  @abstract_model = MerbAdmin::AbstractModel.new(model_name)
118
- find_properties
87
+ get_properties
119
88
  end
120
89
 
121
- def find_properties
90
+ def get_properties
122
91
  @properties = @abstract_model.properties
123
92
  end
124
93
 
125
- def find_object
94
+ def get_object
126
95
  @object = @abstract_model.get(params[:id])
127
96
  raise NotFound unless @object
128
97
  end
129
98
 
130
- def merge_query!(options)
131
- return unless params[:query]
99
+ def sort
100
+ sort = params[:sort]
101
+ sort ? {:sort => sort} : {}
102
+ end
103
+
104
+ def sort_reverse
105
+ sort_reverse = params[:sort_reverse]
106
+ sort_reverse ? {:sort_reverse => sort_reverse == "true"} : {}
107
+ end
108
+
109
+ def query(options)
110
+ query = params[:query]
111
+ return {} unless query
132
112
  statements = []
133
113
  values = []
134
114
  conditions = options[:conditions] || [""]
135
- @properties.each do |property|
136
- next unless property[:type] == :string
115
+
116
+ @properties.select{|property| property[:type] == :string}.each do |property|
137
117
  statements << "#{property[:name]} LIKE ?"
138
- values << "%#{params[:query]}%"
118
+ values << "%#{query}%"
139
119
  end
120
+
140
121
  conditions[0] += " AND " unless conditions == [""]
141
122
  conditions[0] += statements.join(" OR ")
142
123
  conditions += values
143
- options.merge!(:conditions => conditions) unless conditions == [""]
124
+ conditions != [""] ? {:conditions => conditions} : {}
144
125
  end
145
126
 
146
- def merge_filter!(options)
147
- return unless params[:filter]
127
+ def filter(options)
128
+ filter = params[:filter]
129
+ return {} unless filter
148
130
  statements = []
149
131
  values = []
150
132
  conditions = options[:conditions] || [""]
151
- params[:filter].each_pair do |key, value|
152
- @properties.each do |property|
153
- next unless property[:name] == key.to_sym
154
- next unless property[:type] == :boolean
133
+
134
+ filter.each_pair do |key, value|
135
+ @properties.select{|property| property[:type] == :boolean && property[:name] == key.to_sym}.each do |property|
155
136
  statements << "#{key} = ?"
156
137
  values << (value == "true")
157
138
  end
158
139
  end
140
+
159
141
  conditions[0] += " AND " unless conditions == [""]
160
142
  conditions[0] += statements.join(" AND ")
161
143
  conditions += values
162
- options.merge!(:conditions => conditions) unless conditions == [""]
144
+ conditions != [""] ? {:conditions => conditions} : {}
163
145
  end
164
146
 
165
- def merge_sort!(options)
166
- return unless params[:sort]
167
- sort = params[:sort] || "id"
168
- options.merge!(:sort => sort)
147
+ def get_attributes
148
+ @attributes = params[@abstract_model.singular_name] || {}
149
+ # Delete fields that are blank
150
+ @attributes.each do |key, value|
151
+ @attributes[key] = nil if value.blank?
152
+ end
169
153
  end
170
154
 
171
- def merge_sort_reverse!(options)
172
- return unless params[:sort_reverse]
173
- reverse = params[:sort_reverse] == "true"
174
- options.merge!(:sort_reverse => reverse)
155
+ def update_all_associations
156
+ @abstract_model.associations.each do |association|
157
+ ids = (params[:associations] || {}).delete(association[:name])
158
+ case association[:type]
159
+ when :has_one
160
+ update_association(association, ids)
161
+ when :has_many
162
+ update_associations(association, ids.to_a)
163
+ end
164
+ end
175
165
  end
176
166
 
177
167
  def update_association(association, id = nil)
@@ -190,4 +180,23 @@ class MerbAdmin::Main < MerbAdmin::Application
190
180
  end
191
181
  end
192
182
 
183
+ def redirect_on_success
184
+ singular_name = @abstract_model.singular_name
185
+ pretty_name = @abstract_model.pretty_name
186
+ action = params[:action]
187
+ if params[:_continue]
188
+ redirect(url(:merb_admin_edit, :model_name => singular_name, :id => @object.id), :message => {:notice => "#{pretty_name} was successfully #{action}d"})
189
+ elsif params[:_add_another]
190
+ redirect(url(:merb_admin_new, :model_name => singular_name), :message => {:notice => "#{pretty_name} was successfully #{action}d"})
191
+ else
192
+ redirect(url(:merb_admin_list, :model_name => singular_name), :message => {:notice => "#{pretty_name} was successfully #{action}d"})
193
+ end
194
+ end
195
+
196
+ def render_error
197
+ action = params[:action]
198
+ message[:error] = "#{@abstract_model.pretty_name} failed to be #{action}d"
199
+ render(:new, :layout => 'form')
200
+ end
201
+
193
202
  end
@@ -5,8 +5,7 @@
5
5
  label = association[:pretty_name]
6
6
  required = false
7
7
  errors_exist = !(@object.errors[child_key].nil? || @object.errors[child_key].empty?)
8
- @properties.each do |property|
9
- next unless property[:name] == child_key
8
+ @properties.select{|property| property[:name] == child_key}.each do |property|
10
9
  required = true unless property[:nullable?]
11
10
  end
12
11
  %>
@@ -6,8 +6,7 @@
6
6
  label = association[:pretty_name]
7
7
  required = false
8
8
  errors_exist = !(@object.errors[child_key].nil? || @object.errors[child_key].empty?)
9
- @properties.each do |property|
10
- next unless property[:name] == child_key
9
+ @properties.select{|property| property[:name] == child_key}.each do |property|
11
10
  required = true unless property[:nullable?]
12
11
  end
13
12
  %>
@@ -1,11 +1,9 @@
1
1
  <fieldset class="module aligned">
2
2
  <% belongs_to_keys = @abstract_model.belongs_to_associations.map{|b| b[:child_key].first} %>
3
- <% properties.each do |property| %>
3
+ <% properties.reject{|property| [:id, :created_at, :created_on, :deleted_at, :updated_at, :updated_on, :deleted_on].include?(property[:name]) || belongs_to_keys.include?(property[:name])}.each do |property| %>
4
4
  <% property_name = property[:name] %>
5
5
  <% property_type = property[:type] %>
6
6
  <% errors_exist = !(@object.errors[property_name].nil? || @object.errors[property_name].empty?) %>
7
- <% next if [:id, :created_at, :created_on, :deleted_at, :updated_at, :updated_on, :deleted_on].include?(property_name) %>
8
- <% next if belongs_to_keys.include?(property_name) %>
9
7
  <div class="<%= errors_exist ? "form-row errors" : "form-row" %>">
10
8
  <% if errors_exist %>
11
9
  <ul class="errorlist">
@@ -4,8 +4,7 @@
4
4
  <%= @abstract_model.pretty_name %>: <%= link_to(object_name(@object), url(:merb_admin_edit, :model_name => @abstract_model.singular_name, :id => @object.id)) %>
5
5
  <ul>
6
6
  <% @abstract_model.has_many_associations.each do |association| %>
7
- <% @object.send(association[:name]).each do |child| %>
8
- <% next if child.nil? %>
7
+ <% @object.send(association[:name]).reject{|child| child.nil?}.each do |child| %>
9
8
  <li>
10
9
  One or more <%= @abstract_model.pretty_name.pluralize.downcase %> in <%= association[:pretty_name].downcase %>: <%= link_to(object_name(child), url(:merb_admin_edit, :model_name => association[:name].to_s.singularize.to_sym, :id => child.id)) %>
11
10
  </li>
@@ -6,36 +6,27 @@ module MerbAdmin
6
6
  def self.all
7
7
  return @models if @models
8
8
  @models ||= []
9
- case Merb.orm
10
- when :activerecord
9
+ orm = Merb.orm
10
+ case orm
11
+ when :activerecord, :sequel
11
12
  Dir.glob(Merb.dir_for(:model) / Merb.glob_for(:model)).each do |filename|
12
- # FIXME: This heuristic for finding ActiveRecord models could be too strict
13
- File.read(filename).scan(/^class ([\w\d_\-:]+) < ActiveRecord::Base$/).flatten.each do |m|
14
- model = lookup(m.to_s.to_sym)
13
+ File.read(filename).scan(/class ([\w\d_\-:]+)/).flatten.each do |model_name|
14
+ model = lookup(model_name.to_sym)
15
15
  @models << new(model) if model
16
16
  end
17
17
  end
18
- @models.sort!{|a, b| a.model.to_s <=> b.model.to_s}
19
18
  when :datamapper
20
- DataMapper::Resource.descendants.each do |m|
19
+ @models = []
20
+ DataMapper::Model.descendants.each do |model_name|
21
21
  # Remove DataMapperSessionStore because it's included by default
22
22
  next if m == Merb::DataMapperSessionStore if Merb.const_defined?(:DataMapperSessionStore)
23
- model = lookup(m.to_s.to_sym)
23
+ model = lookup(model_name.to_s.to_sym)
24
24
  @models << new(model) if model
25
25
  end
26
- @models.sort!{|a, b| a.model.to_s <=> b.model.to_s}
27
- when :sequel
28
- Dir.glob(Merb.dir_for(:model) / Merb.glob_for(:model)).each do |filename|
29
- # FIXME: This heuristic for finding Sequel models could be too strict
30
- File.read(filename).scan(/^class ([\w\d_\-:]+) < Sequel::Model$/).flatten.each do |m|
31
- model = lookup(m.to_s.to_sym)
32
- @models << new(model) if model
33
- end
34
- end
35
- @models.sort!{|a, b| a.model.to_s <=> b.model.to_s}
36
26
  else
37
- raise "MerbAdmin does not support the #{Merb.orm} ORM"
27
+ raise "MerbAdmin does not support the #{orm} ORM"
38
28
  end
29
+ @models.sort!{|x, y| x.model.to_s <=> y.model.to_s}
39
30
  end
40
31
 
41
32
  # Given a symbol +model_name+, finds the corresponding model class
@@ -48,22 +39,24 @@ module MerbAdmin
48
39
 
49
40
  case Merb.orm
50
41
  when :activerecord
51
- return model if superclasses(model).include?(ActiveRecord::Base)
42
+ model if superclasses(model).include?(ActiveRecord::Base)
52
43
  when :datamapper
53
- return model if model.include?(DataMapper::Resource)
44
+ model if model.include?(DataMapper::Resource)
54
45
  when :sequel
55
- return model if superclasses(model).include?(Sequel::Model)
46
+ model if superclasses(model).include?(Sequel::Model)
47
+ else
48
+ nil
56
49
  end
57
- nil
58
50
  end
59
51
 
60
52
  attr_accessor :model
61
53
 
62
54
  def initialize(model)
63
55
  model = self.class.lookup(model.to_s.camel_case) unless model.is_a?(Class)
56
+ orm = Merb.orm
64
57
  @model = model
65
58
  self.extend(GenericSupport)
66
- case Merb.orm
59
+ case orm
67
60
  when :activerecord
68
61
  require 'activerecord_support'
69
62
  self.extend(ActiverecordSupport)
@@ -74,7 +67,7 @@ module MerbAdmin
74
67
  require 'sequel_support'
75
68
  self.extend(SequelSupport)
76
69
  else
77
- raise "MerbAdmin does not support the #{Merb.orm} ORM"
70
+ raise "MerbAdmin does not support the #{orm} ORM"
78
71
  end
79
72
  end
80
73
 
@@ -133,6 +133,10 @@ module MerbAdmin
133
133
  end
134
134
 
135
135
  module InstanceMethods
136
+ def update_attributes(attributes)
137
+ update(attributes)
138
+ end
139
+
136
140
  def clear_association(association)
137
141
  association.clear
138
142
  end
@@ -92,7 +92,7 @@ def load_data
92
92
  end
93
93
 
94
94
  puts "Loading current MLB leagues, divisions, teams, and players"
95
- MLB::Teams.all.each do |mlb_team|
95
+ MLB::Team.all.each do |mlb_team|
96
96
  unless league = MerbAdmin::AbstractModel.new("League").first(:conditions => ["name = ?", mlb_team.league])
97
97
  league = MerbAdmin::AbstractModel.new("League").create(:name => mlb_team.league)
98
98
  end
@@ -102,8 +102,7 @@ def load_data
102
102
  unless team = MerbAdmin::AbstractModel.new("Team").first(:conditions => ["name = ?", mlb_team.name])
103
103
  team = MerbAdmin::AbstractModel.new("Team").create(:name => mlb_team.name, :logo_url => mlb_team.logo_url, :manager => mlb_team.manager, :ballpark => mlb_team.ballpark, :mascot => mlb_team.mascot, :founded => mlb_team.founded, :wins => mlb_team.wins, :losses => mlb_team.losses, :win_percentage => ("%.3f" % (mlb_team.wins.to_f / (mlb_team.wins + mlb_team.losses))).to_f, :division => division, :league => league)
104
104
  end
105
- mlb_team.players.each do |player|
106
- next if player.number.nil?
105
+ mlb_team.players.reject{|player| player.number.nil?}.each do |player|
107
106
  MerbAdmin::AbstractModel.new("Player").create(:name => player.name, :number => player.number, :position => player.position, :team => team)
108
107
  end
109
108
  end
@@ -114,8 +113,8 @@ def copy_models(orm = nil)
114
113
  puts "Copying sample #{orm} models into host application - resolves any collisions"
115
114
  seen, copied, duplicated = [], [], []
116
115
  Dir.glob(File.dirname(__FILE__) / ".." / ".." / "spec" / "models" / orm.to_s.downcase / MerbAdmin.glob_for(:model)).each do |source_filename|
117
- destination_filename = Merb.dir_for(:model) / File.basename(source_filename)
118
116
  next if seen.include?(source_filename)
117
+ destination_filename = Merb.dir_for(:model) / File.basename(source_filename)
119
118
  mirror_file(source_filename, destination_filename, copied, duplicated)
120
119
  seen << source_filename
121
120
  end
@@ -128,8 +127,8 @@ def copy_migrations(orm = nil)
128
127
  puts "Copying sample #{orm} migrations into host application - resolves any collisions"
129
128
  seen, copied, duplicated = [], [], []
130
129
  Dir.glob(File.dirname(__FILE__) / ".." / ".." / "spec" / "migrations" / orm.to_s.downcase / "*.rb").each do |source_filename|
131
- destination_filename = Merb.root / "schema" / "migrations" / File.basename(source_filename)
132
130
  next if seen.include?(source_filename)
131
+ destination_filename = Merb.root / "schema" / "migrations" / File.basename(source_filename)
133
132
  mirror_file(source_filename, destination_filename, copied, duplicated)
134
133
  seen << source_filename
135
134
  end
data/lib/merb-admin.rb CHANGED
@@ -23,7 +23,7 @@ if defined?(Merb::Plugins)
23
23
 
24
24
  # Slice metadata
25
25
  self.description = "MerbAdmin is a Merb plugin that provides an easy-to-use interface for managing your data."
26
- self.version = "0.6.2"
26
+ self.version = "0.6.3"
27
27
  self.author = "Erik Michaels-Ober"
28
28
 
29
29
  # Stub classes loaded hook - runs before LoadClasses BootLoader
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: merb-admin
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.2
4
+ version: 0.6.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Erik Michaels-Ober
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-11-02 00:00:00 -08:00
12
+ date: 2009-11-05 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -20,7 +20,7 @@ dependencies:
20
20
  requirements:
21
21
  - - ">="
22
22
  - !ruby/object:Gem::Version
23
- version: 1.0.12
23
+ version: 1.0.15
24
24
  version:
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: merb-assets
@@ -30,7 +30,7 @@ dependencies:
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 1.0.12
33
+ version: 1.0.15
34
34
  version:
35
35
  - !ruby/object:Gem::Dependency
36
36
  name: merb-helpers
@@ -40,7 +40,7 @@ dependencies:
40
40
  requirements:
41
41
  - - ">="
42
42
  - !ruby/object:Gem::Version
43
- version: 1.0.12
43
+ version: 1.0.15
44
44
  version:
45
45
  - !ruby/object:Gem::Dependency
46
46
  name: builder