dm-cutie-ui 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
File without changes
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (C) 2009, Cory ODaniel
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a
4
+ copy of this software and associated documentation files (the "Software"),
5
+ to deal in the Software without restriction, including without limitation
6
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
7
+ and/or sell copies of the Software, and to permit persons to whom the
8
+ Software is furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
16
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19
+ DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,61 @@
1
+ Description
2
+ =============
3
+ dm-cutie-ui is a live reporting tool for dm-cutie. http://github.com/coryodaniel/dm-cutie
4
+
5
+
6
+ Adding Custom Columns
7
+ ======================
8
+ The partial 'grid' takes three keys to create its local variables: :columns, :records, :adhoc_columns (discussed next)
9
+
10
+ Columns should be respond to #each, it will generally be a DataMapper PropertySet. Each element in columns will be used in a #send method call on each of the elements in records. That means instead of doing the standard
11
+ partial :grid, :locals => { :columns => MyModel.properties, :records => @my_collection}
12
+
13
+ You can add any other columns you want as long as there is a method that a 'record' will respond to. For example, every object has a 'class' method, so you could do
14
+ partial :grid,
15
+ :locals => {
16
+ :columns => MyModel.properties.to_a + [:class],
17
+ :records => @my_collection
18
+ }
19
+
20
+ This would cause the class name to be output in a column (pretty useless), but you can add any method you want to the class and simply add its name to the set of elements being passed to :columns
21
+
22
+
23
+ As an alternative method you can pass a column name to a proc in the :adhoc_columns parameter
24
+ partial :grid,
25
+ :locals => {
26
+ :columns => MyModel.properties,
27
+ :records => @my_collection,
28
+ :adhoc_columns => {
29
+ :my_cool_class_name => lambda{|my_record| my_record.class }
30
+ }
31
+ }
32
+
33
+ This would result in a column named 'my_cool_class_name' with a value of 'MyModel'. Obviously you can be more creative :)
34
+
35
+ Note: the proc should accept one parameter, the specific record from the collection of items passed to :records
36
+
37
+ IMPORTANT NOTE:
38
+ Remember, if you are adding additional columns to the grid, make sure you pass the column names to the 'menu' partial if you want the ability to hide that column.
39
+
40
+
41
+ DataMapper Default Context
42
+ ==========================
43
+ DataMapper requires a 'default' repository. In DM UI all users use their own repository, so a fake repository is stubbed as
44
+
45
+ DataMapper.setup :default, "abstract://null"
46
+
47
+ All calls should be done through the Sinatra helper method #repo.
48
+
49
+
50
+ TODOS
51
+ =====
52
+ * If you boot a server with extras and then browse to a dm-cutie repo with out those extras you get an error
53
+ * should probably change extras loaded to a 'per repository' thing
54
+ * Make *.erbs more dry, its probably possible to get ride of them all together if the hooks had the following methods display_views, display_relationships
55
+ * Make this app less ugly, I suck horribly at CSS :)
56
+ * Deal w/ the super fields
57
+ * --include-hooks=this,that/there,etc
58
+ * figure out how to support including hooks/views that aren't a part of dm-cutie or dm-cutie-extras
59
+ * dm-pagination
60
+ * If someone built a merb-slice version of this, they would be awesome.
61
+ * Sinatra shutdown hook to clean up the tmp directory
data/Rakefile ADDED
@@ -0,0 +1,100 @@
1
+ require 'rubygems'
2
+ require 'rake/gempackagetask'
3
+ require 'rubygems/specification'
4
+ require 'date'
5
+ require 'merb-core/version'
6
+ require 'merb-core/tasks/merb_rake_helper'
7
+ require "extlib"
8
+
9
+ require 'rake'
10
+ require 'rake/clean'
11
+ require 'spec/rake/spectask'
12
+ require "spec"
13
+ require 'rake/rdoctask'
14
+ require 'rake/gempackagetask'
15
+
16
+ ROOT = Pathname(__FILE__).dirname.expand_path
17
+ require ROOT + 'lib/dm-cutie-ui/version'
18
+
19
+ @spec = Gem::Specification.new do |s|
20
+ s.name = %q{dm-cutie-ui}
21
+ s.version = DmCutieUI::VERSION
22
+
23
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
24
+ s.authors = ["Cory ODaniel"]
25
+ s.date = %q{2009-10-15}
26
+ s.summary = s.description = %q{An interface to DM Cutie repos.}
27
+ s.email = %q{cutie@coryodaniel.com}
28
+ s.bindir = 'bin'
29
+ s.executables = ['dm-cutie-ui']
30
+ s.extra_rdoc_files = ["README.markdown", "LICENSE", "History.txt"]
31
+ s.files = ["LICENSE", "README.markdown", "Rakefile", "History.txt",
32
+ "config.ru",
33
+ "bin/dm-cutie-ui",
34
+ "lib/dm-cutie-ui.rb",
35
+ "lib/dm-cutie-ui/config.rb",
36
+ "lib/dm-cutie-ui/server.rb",
37
+ "lib/dm-cutie-ui/version.rb",
38
+ ]
39
+ s.files += Dir["lib/dm-cutie-ui/server/**/*"]
40
+ s.has_rdoc = true
41
+ s.homepage = "http://github.com/coryodaniel/dm-cutie-ui"
42
+
43
+ s.add_dependency 'sinatra', '=0.9.4'
44
+ s.add_dependency 'extlib', ">=0.9.13"
45
+ s.add_dependency "dm-core", ">=0.10.1"
46
+ s.add_dependency "dm-aggregates", ">=0.10.1"
47
+ s.add_dependency "data_objects", '>=0.10.0'
48
+ s.add_dependency "dm-cutie", '>=0.3.0'
49
+ s.require_paths = ["lib"]
50
+ s.rubygems_version = %q{1.2.0}
51
+ end
52
+
53
+ [ ROOT, ROOT.parent ].each do |dir|
54
+ Pathname.glob(dir.join('tasks/**/*.rb').to_s).each { |f| require f }
55
+ end
56
+
57
+ NAME = @spec.name
58
+ GEM_VERSION = DmCutieUI::VERSION
59
+
60
+ Rake::GemPackageTask.new(@spec) do |pkg|
61
+ pkg.gem_spec = @spec
62
+ end
63
+
64
+ desc "install the plugin locally"
65
+ task :install => [:package] do
66
+ sh %{sudo gem install #{install_home} pkg/#{NAME}-#{GEM_VERSION} --no-update-sources}
67
+ end
68
+
69
+ desc "create a gemspec file"
70
+ task :make_spec do
71
+ File.open("#{NAME}.gemspec", "w") do |file|
72
+ file.puts @spec.to_ruby
73
+ end
74
+ end
75
+
76
+ Rake::RDocTask.new do |rdoc|
77
+ files = ["README.markdown", "History.txt", "LICENSE", "lib/**/*.rb"]
78
+ rdoc.rdoc_files.add(files)
79
+ rdoc.main = "README.markdown"
80
+ rdoc.title = "DM CutieUI"
81
+
82
+ rdoc.rdoc_dir = "doc/rdoc"
83
+ rdoc.options << "--line-numbers" << "--inline-source"
84
+ end
85
+
86
+ Spec::Rake::SpecTask.new do |t|
87
+ t.spec_files = Dir["./spec/**/*_spec.rb"]
88
+ t.spec_files.unshift './spec/spec_helper.rb'
89
+
90
+ t.libs = ['lib']
91
+ t.spec_opts << "--color" << "--format" << "specdoc" #"progress"
92
+
93
+ if ENV['RCOV']
94
+ t.rcov = true
95
+ t.rcov_opts << '--exclude' << 'pkg,spec,interactive.rb,install_test_suite.rb,lib/gems,' + Gem.path.join(',')
96
+ t.rcov_opts << '--text-summary'
97
+ t.rcov_opts << '--sort' << 'coverage' << '--sort-reverse'
98
+ t.rcov_opts << '--only-uncovered'
99
+ end
100
+ end
data/bin/dm-cutie-ui ADDED
@@ -0,0 +1,50 @@
1
+ #! /usr/bin/env ruby
2
+ require 'rubygems' #its poison, i know.
3
+
4
+ if `which rackup`.empty?
5
+ abort "** Can't find `rackup` in PATH."
6
+ end
7
+
8
+ if ARGV.include?('-h') || ARGV.include?('--help')
9
+ puts <<-USAGE_INFO
10
+ Usage: dm-cutie-ui [cutie-options] [ruby-options] [rack-options]
11
+
12
+ Starts the dm-cutie front end
13
+
14
+ DmCutieUI Options:
15
+ ==================================================
16
+ --extras= # A comma seperated list of extras for dm-cutie to look for
17
+ (should match what you had in your app)
18
+ Examples:
19
+ dm-cutie-ui --extras=sqlite3_execution_plan
20
+ dm-cutie-ui --extras=mysql_execution_plan,mysql_warning
21
+
22
+ Rack Options:
23
+ ==================================================
24
+ -s, --server SERVER serve using SERVER (webrick/mongrel)
25
+ -o, --host HOST listen on HOST (default: 0.0.0.0)
26
+ -p, --port PORT use PORT (default: 9292)
27
+ -E, --env ENVIRONMENT use ENVIRONMENT for defaults (default: development)
28
+ -D, --daemonize run daemonized in the background
29
+ -P, --pid FILE file to store PID (default: rack.pid)
30
+
31
+ USAGE_INFO
32
+
33
+ else
34
+ __DIR__ = File.expand_path( File.join(File.dirname(__FILE__), '..') )
35
+
36
+ # Simple ARGV Parser, @note include-hooks is a TODO
37
+ # Remove cutie's argv from ARGV and let Sinatra have it.
38
+ cutie_flags = [:extras, :'include-hooks']
39
+ cutie_argv = ARGV.select{|arg| arg =~ /(\-\-(#{cutie_flags.join('|')}))/}
40
+ ARGV.delete_if{|arg| cutie_argv.member?(arg)}
41
+
42
+ args = ARGV
43
+ ENV['RUBYLIB'] = ENV['RUBYLIB'].to_s + ':' + File.join(__DIR__,'lib')
44
+ args.unshift '-e', %Q{require "dm-cutie-ui"; CUTIE_ARGV=%w{#{cutie_argv.join(' ')}}}
45
+ args.push File.expand_path(
46
+ File.join(__DIR__, "config.ru")
47
+ )
48
+
49
+ exec "rackup", *args
50
+ end
data/config.ru ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift File.expand_path(
4
+ File.join(File.dirname(__FILE__), 'lib')
5
+ )
6
+ require 'dm-cutie-ui/config'
7
+ require 'dm-cutie-ui/server'
8
+
9
+ use Rack::ShowExceptions
10
+ run DmCutieUI::Server.new
@@ -0,0 +1,107 @@
1
+ require 'rubygems'
2
+ require 'digest/md5'
3
+ require 'logger'
4
+
5
+ gem 'extlib', ">=0.9.13"
6
+ require 'extlib'
7
+
8
+ gem 'dm-cutie', '>=0.3.0'
9
+ require 'dm-cutie'
10
+
11
+ gem 'dm-aggregates', '>=0.10.1'
12
+ require 'dm-aggregates'
13
+
14
+ gem 'dm-core', '>=0.10.1'
15
+ require 'dm-core'
16
+
17
+ gem "data_objects", '>=0.10.0'
18
+ require 'data_objects'
19
+
20
+ # SEt up a faux adapter. DM requires a default repository
21
+ # Repository names are hashes of the Normalized URI and are stored in CutieUI.
22
+ DataMapper.setup :default, "abstract://null"
23
+
24
+ module DmCutieUI
25
+ class << self
26
+ def logger
27
+ @_logger ||= Logger.new(STDOUT)
28
+ end
29
+ def view_root
30
+ @_view_root ||= File.join('', 'tmp', 'dm-cutie-ui', Time.now.to_i.to_s)
31
+ end
32
+ # - routes - Routes for cutie models
33
+ #
34
+ def routes
35
+ @__routes ||={}
36
+ end
37
+
38
+ # - repos - Cache of connection strings used since boot time
39
+ #
40
+ # @return [String] connection string
41
+ def repos
42
+ @__repos ||= {}
43
+ end
44
+
45
+ # - connect - Connects to a datamapper repository
46
+ # This takes the password as an additional parameter for 'security' reasons since
47
+ # it caches all connection strings for a user
48
+ #
49
+ # @param connection [Hash]
50
+ # - string [String] connection string
51
+ # - password [String] connection password
52
+ #
53
+ # @return [String] -
54
+ #
55
+ def connect( connection )
56
+ connection_options = DataMapper::Adapters.send(:normalize_options, connection[:string])
57
+
58
+ # Cache this before adding the password if the person decided they didn't want it cached by leaving it out
59
+ normalized_uri = begin
60
+ query = connection_options.except(:adapter, :user, :password, :host, :port, :path, :fragment, :scheme, :query, :username, :database)
61
+ query = nil if query.empty?
62
+
63
+ DataObjects::URI.new(
64
+ connection_options[:adapter],
65
+ connection_options[:user] || connection_options[:username],
66
+ nil, #Dont put the password in the cache
67
+ connection_options[:host],
68
+ connection_options[:port],
69
+ connection_options[:path] || connection_options[:database],
70
+ query,
71
+ connection_options[:fragment]
72
+ )
73
+ end
74
+
75
+ # Create a hash of the normalized_uri
76
+ token = Digest::MD5.hexdigest(normalized_uri.to_s).to_sym
77
+
78
+ # Cache the uri
79
+ DmCutieUI.repos[token] = normalized_uri.to_s
80
+
81
+ # Add the password if it was provided
82
+ connection_options[:password] = connection[:password] unless connection[:password].blank?
83
+
84
+ adapter = DataMapper::Adapters.new token, connection_options
85
+
86
+ DataMapper::Repository.adapters[adapter.name] = adapter
87
+
88
+ if DataMapper::Cutie.valid_repo? adapter.name
89
+ return token
90
+ else
91
+ return false
92
+ end
93
+ end
94
+
95
+ def root
96
+ @_root_path ||= File.expand_path(File.dirname(__FILE__)) / 'dm-cutie-ui'
97
+ end
98
+ end
99
+ end
100
+
101
+ require DmCutieUI.root / :version
102
+
103
+ class String
104
+ def truncate(len,repl='...')
105
+ (self.length <= (len - repl.length)) ? self : self.slice(0,len) + repl.to_s
106
+ end
107
+ end
@@ -0,0 +1,63 @@
1
+ require 'fileutils'
2
+ puts CUTIE_ARGV
3
+
4
+ cutie_ui_config = CUTIE_ARGV.inject({}) do |conf, arg|
5
+ config_key, config_vals = arg.split('=')
6
+
7
+ if config_key
8
+ # { :extras => ['mysql', 'sqlite3'] }
9
+ config_value = config_vals.blank? ? true : config_vals.split(',')
10
+
11
+ conf[config_key.gsub('--','').to_sym] = config_value
12
+ conf
13
+ else
14
+ conf
15
+ end
16
+ end
17
+
18
+
19
+ # dm-cutie-ui has a bunch of views, but views may also come from dm-cutie-extras and eventually add'l plugins
20
+ # since we need a path to all the views, we create a temp folder and copy the views their
21
+ # as well as any other views from additional gems/reqs
22
+
23
+ # Configure DmCutieUI
24
+ FileUtils.mkdir_p DmCutieUI.view_root
25
+ FileUtils.cp_r(
26
+ File.join(DmCutieUI.root, "server", "views"), DmCutieUI.view_root
27
+ )
28
+ DmCutieUI.logger.info "View temp directory: #{DmCutieUI.view_root}"
29
+
30
+
31
+ # If extras were requested, get them.
32
+ if cutie_ui_config[:extras]
33
+ begin
34
+ require 'dm-cutie-extras'
35
+ rescue LoadError => ex
36
+ DmCutieUI.logger.error "dm-cutie-extras were requested, but the gem was not found: gem install dm-cutie-extras"
37
+ exit(1)
38
+ end
39
+
40
+ cutie_ui_config[:extras].each do |extra|
41
+ begin
42
+ # Load the extra
43
+ DataMapper::Cutie::Extras.load extra.to_sym
44
+
45
+ # move the hook's view into the DmCutieUI.view_root/cutie_models directory
46
+ #/tmp/dm-cutie-ui/view/1258150564/views/cutie_models/#{extra}.erb
47
+ # render a extras views by doing
48
+ # render :'cutie_models/#{extra}'
49
+
50
+ FileUtils.cp DataMapper::Cutie::Extras.view_path[extra.to_sym], DmCutieUI.view_root / 'views' / 'cutie_models'
51
+ rescue LoadError => ex
52
+ DmCutieUI.logger.error "dm-cutie-extra '#{extra}' does not exist."
53
+ exit(2)
54
+ end
55
+ end
56
+ end
57
+
58
+ # Thanks to dkubb: this make sure that the PropertySet always contains remote keys
59
+ descendants = DataMapper::Model.descendants.to_a
60
+ while model = descendants.shift
61
+ descendants.concat(model.descendants.to_a - [ model ])
62
+ model.send(:assert_valid)
63
+ end
@@ -0,0 +1,222 @@
1
+ require 'sinatra/base'
2
+ require 'erb'
3
+
4
+ module DmCutieUI
5
+ class Server < Sinatra::Base
6
+ dir = File.dirname(File.expand_path(__FILE__))
7
+ set :sessions, true
8
+ set :static, true
9
+ set :public, dir / "server" / "public"
10
+ set :views, DmCutieUI.view_root / 'views'
11
+
12
+ # BEGIN ROUTES
13
+ get('/help') { erb :'default/help' }
14
+
15
+ get '/' do
16
+ session["history"].each do |repo_key|
17
+ # Remove the key from the cookie, it was from a previous server boot
18
+ session["history"].delete(repo_key) if DmCutieUI.repos[repo_key].blank?
19
+ end if session["history"]
20
+
21
+ session.delete('current') if params['disconnect']
22
+
23
+ if !DmCutieUI.repos[session["current"]].blank?
24
+ erb :'default/index'
25
+ else
26
+ erb :'default/login'
27
+ end
28
+ end
29
+
30
+ post '/' do
31
+ begin
32
+ # This will be used by the repo method to get access to the repo the user selected
33
+ repo_key = DmCutieUI.connect params[:connection]
34
+
35
+ if repo_key
36
+ session["history"] ||= []
37
+
38
+ session["history"] << repo_key unless session["history"].member?(repo_key)
39
+ session["current"] = repo_key.to_sym
40
+ erb :'default/index'
41
+ else
42
+ @connection_error = "That repository is missing some dm-cutie storages (#{DataMapper::Cutie.missing_storage.join(', ')})"
43
+ erb :'default/login'
44
+ end
45
+ rescue Exception => ex
46
+ # DataObjects::SyntaxError, LoadError
47
+ @connection_error = ex.message
48
+ erb :'default/login'
49
+ end
50
+ end
51
+
52
+
53
+ ###################### GENERATE ROUTES ####################
54
+ # Generate routes for all files in 'sinatra/views/cutie_models'
55
+ # TODO: Create routes for --include-hooks once its supported
56
+ DataMapper::Cutie::MODELS.each do |model|
57
+ view_name = model.to_s.pluralize
58
+ view_path = DmCutieUI.view_root / 'views' / 'cutie_models' / "#{view_name}.erb"
59
+ view_uri = "/#{view_name}"
60
+ if File.exist? view_path
61
+ DmCutieUI.routes[view_uri] = {
62
+ :model => model,
63
+ :file => view_path,
64
+ :view_name => view_name
65
+ }
66
+
67
+ # Create the 'controller'
68
+ get view_uri do
69
+ if !DmCutieUI.repos[session["current"]].blank?
70
+ # The cutie model being viewed
71
+
72
+ @view_name = DmCutieUI.routes[ request.path_info ][:view_name]
73
+ @cutie_model = DataMapper::Cutie.get_klass DmCutieUI.routes[ request.path_info ][:model]
74
+
75
+ @title = DmCutieUI.routes[ request.path_info ][:model]
76
+
77
+ # Keep the response scoped to the users selected Cutie Repo
78
+ user_current_repo { erb(:"cutie_models/#{@view_name}") }
79
+ else
80
+ @connection_error = "Select a DM repository to connect to"
81
+ redirect '/'
82
+ end
83
+ end
84
+
85
+ elsif !@model.blank?
86
+ puts "A view was not found for: #{@model}. This is probably an anonymous resource."
87
+ end # else probably an anonymous resource
88
+ end
89
+
90
+ # END ROUTES
91
+
92
+ # BEGIN HELPERS
93
+ helpers do
94
+ include Rack::Utils
95
+ alias_method :h, :escape_html
96
+
97
+ ################
98
+ # DM Cutie UI doesn't need your applications models
99
+ # she knows what she needs to know about them through
100
+ # what DM Cutie stored in her tables
101
+ # TODO - Remove the need for uniq by grouping these, also consider a smart way to cache them per user
102
+ ################
103
+
104
+ # Gets a list of repo names from the Cutie Repo
105
+ def repository_names
106
+ user_current_repo do
107
+ RepositoryStorage.all().map{ |rs| rs.repo_name }.uniq
108
+ end
109
+ end
110
+
111
+ # Gets a list of model names from the Cutie Repo
112
+ def model_names
113
+ user_current_repo do
114
+ RepositoryStorage.all().map{ |rs| rs.model_name }.uniq
115
+ end
116
+ end
117
+
118
+ # Gets a list of adapter names from the Cutie Repo
119
+ def adapter_names
120
+ user_current_repo do
121
+ RepositoryStorage.all().map{ |rs| rs.adapter_name }.uniq
122
+ end
123
+ end
124
+
125
+ # Get the users chosen repository context
126
+ def user_current_repo
127
+ repository( session["current"] ) { yield }
128
+ end
129
+
130
+ def partial(template, *args)
131
+ template = File.join('shared',"_#{template}").to_sym
132
+ options = args.last.is_a?(Hash) ? args.pop : {}
133
+ options.merge!(:layout => false)
134
+
135
+
136
+ if collection = options.delete(:collection) then
137
+ collection.inject([]) do |buffer, member|
138
+ buffer << erb(template, options.merge(
139
+ :layout => false,
140
+ :locals => {template.to_sym => member}
141
+ )
142
+ )
143
+ end.join("\n")
144
+ else
145
+ erb(template, options)
146
+ end
147
+ end
148
+
149
+ # Parses the params hash looking for params that are properties of the model
150
+ #
151
+ def parse_params(model)
152
+ params.only *model.properties.map{|p| p.name.to_s} # Have to string this since sinatra params isnt a mash
153
+ end
154
+
155
+ def link_to(text,href)
156
+ %Q{<a href="#{href}">#{text}</a>}
157
+ end
158
+
159
+ # ram_filters - Filters for repository, adapter, and model
160
+ #
161
+ # An access for params[*_filter]
162
+ # Should be passed to determine the records to pass to display (Default provided: _grid partial)
163
+ def ram_filters
164
+ {
165
+ :repository => params['repository_filter'],
166
+ :adapter => params['adapter_filter'],
167
+ :model => params['model_filter']
168
+ }
169
+ end
170
+
171
+ # This is just a helper to get the property name or return the symbol if multiple data types are passed to
172
+ # the 'grid' partials :columns attribute
173
+ #
174
+ # @param col [DataMapper::Property|Symbol]
175
+ # @returns [Symbol]
176
+ #
177
+ def column_name(col)
178
+ if col.is_a?(Symbol)
179
+ return col
180
+ else
181
+ return col.name.to_sym
182
+ end
183
+ end
184
+
185
+ # Adds a help link to the top of the page
186
+ def help_link
187
+ @help_link = %q{<a href="#help" class="help_link">help</a>}
188
+ end
189
+
190
+ # Creates a hyperlink to a filtered related model
191
+ #
192
+ def relationship_link(relationship, record)
193
+ relationship_name = relationship.name
194
+
195
+ # This isnt going to work if multipart keys are ever used because its just doing parent_key.first
196
+ if relationship.parent_model == @cutie_model
197
+ filter_value = record.send relationship.parent_key.first.name
198
+ remote_model_key = relationship.child_key.first.name
199
+ remote_model = relationship.child_model
200
+ else #its the child model
201
+ filter_value = record.send relationship.child_key.first.name
202
+ remote_model_key = relationship.parent_key.first.name
203
+ remote_model = relationship.parent_model
204
+ end
205
+
206
+ remote_model_name = DataMapper::Cutie.get_human_name(remote_model).to_s.pluralize
207
+ total_remote_records = remote_model.all( remote_model_key => filter_value ).count
208
+ link_to "View: #{total_remote_records}", "/#{remote_model_name}?#{remote_model_key}=#{filter_value}"
209
+ end
210
+
211
+ # Returns 'selected="selected"' to reselect filter drop downs
212
+ def apply_selected_attribute(filter_name, filter_value)
213
+ if ram_filters[filter_name] == filter_value
214
+ 'selected="SELECTED"'
215
+ end
216
+ end
217
+ end
218
+
219
+ # END HELPERS
220
+
221
+ end
222
+ end