ardm-rails 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/.gitignore +35 -0
- data/.travis.yml +11 -0
- data/Gemfile +47 -0
- data/LICENSE +20 -0
- data/README.rdoc +595 -0
- data/Rakefile +4 -0
- data/VERSION +1 -0
- data/ardm-rails.gemspec +27 -0
- data/lib/ardm-rails.rb +1 -0
- data/lib/dm-rails/configuration.rb +76 -0
- data/lib/dm-rails/mass_assignment_security.rb +89 -0
- data/lib/dm-rails/middleware/identity_map.rb +20 -0
- data/lib/dm-rails/multiparameter_attributes.rb +167 -0
- data/lib/dm-rails/railtie.rb +100 -0
- data/lib/dm-rails/railties/controller_runtime.rb +45 -0
- data/lib/dm-rails/railties/database.rake +106 -0
- data/lib/dm-rails/railties/i18n_support.rb +12 -0
- data/lib/dm-rails/railties/log_listener.rb +39 -0
- data/lib/dm-rails/railties/log_subscriber.rb +54 -0
- data/lib/dm-rails/session_store.rb +70 -0
- data/lib/dm-rails/setup.rb +84 -0
- data/lib/dm-rails/storage.rb +209 -0
- data/lib/dm-rails/version.rb +5 -0
- data/lib/dm-rails.rb +1 -0
- data/lib/generators/data_mapper/migration/migration_generator.rb +30 -0
- data/lib/generators/data_mapper/migration/templates/migration.rb +23 -0
- data/lib/generators/data_mapper/model/model_generator.rb +23 -0
- data/lib/generators/data_mapper/model/templates/model.rb +11 -0
- data/lib/generators/data_mapper/observer/observer_generator.rb +19 -0
- data/lib/generators/data_mapper/observer/templates/observer.rb +7 -0
- data/lib/generators/data_mapper.rb +82 -0
- data/spec/models/fake.rb +31 -0
- data/spec/models/topic.rb +11 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +19 -0
- data/spec/unit/mass_assignment_security_spec.rb +43 -0
- data/spec/unit/multiparameter_attributes_spec.rb +168 -0
- data/tasks/clean.rake +6 -0
- data/tasks/spec.rake +17 -0
- data/tasks/yard.rake +9 -0
- data/tasks/yardstick.rake +20 -0
- metadata +188 -0
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'active_support/core_ext/hash/except'
|
2
|
+
require 'active_support/core_ext/class/attribute_accessors'
|
3
|
+
|
4
|
+
module Rails
|
5
|
+
module DataMapper
|
6
|
+
|
7
|
+
mattr_accessor :configuration
|
8
|
+
|
9
|
+
class Configuration
|
10
|
+
|
11
|
+
attr_accessor :raw
|
12
|
+
attr_accessor :root
|
13
|
+
|
14
|
+
def self.create
|
15
|
+
Rails::DataMapper.configuration ||= new
|
16
|
+
end
|
17
|
+
|
18
|
+
def environments
|
19
|
+
raw.keys
|
20
|
+
end
|
21
|
+
|
22
|
+
def repositories
|
23
|
+
@repositories ||= raw.reject { |k,v| k =~ /defaults/ }.inject({}) do |repositories, pair|
|
24
|
+
environment, config = pair.first, pair.last
|
25
|
+
repositories[environment] = begin
|
26
|
+
c = config['repositories'] || {}
|
27
|
+
c['default'] = config.except('repositories') if config.except('repositories')
|
28
|
+
normalize_repository_config(c)
|
29
|
+
end
|
30
|
+
repositories
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def resource_naming_convention
|
35
|
+
@resource_naming_convention ||= {}
|
36
|
+
end
|
37
|
+
|
38
|
+
def field_naming_convention
|
39
|
+
@field_naming_convention ||= {}
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def normalize_repository_config(hash)
|
45
|
+
config = {}
|
46
|
+
hash.each do |key, value|
|
47
|
+
|
48
|
+
config[key] = if value.kind_of?(Hash)
|
49
|
+
normalize_repository_config(value)
|
50
|
+
elsif key == 'port'
|
51
|
+
value.to_i
|
52
|
+
elsif key == 'adapter' && value == 'postgresql'
|
53
|
+
'postgres'
|
54
|
+
elsif (key == 'database' || key == 'path') && hash['adapter'] =~ /sqlite/
|
55
|
+
value == ':memory:' ? value : File.expand_path(hash[key], root)
|
56
|
+
else
|
57
|
+
value
|
58
|
+
end
|
59
|
+
|
60
|
+
# FIXME Rely on a new dm-sqlite-adapter to do the right thing
|
61
|
+
# For now, we need to make sure that both 'path' and 'database'
|
62
|
+
# point to the same thing, since dm-sqlite-adapter always passes
|
63
|
+
# both to the underlying do_sqlite3 adapter and there's no
|
64
|
+
# guarantee which one will be used
|
65
|
+
|
66
|
+
config['path'] = config[key] if key == 'database'
|
67
|
+
config['database'] = config[key] if key == 'path'
|
68
|
+
|
69
|
+
end
|
70
|
+
config
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'dm-core'
|
2
|
+
require 'active_support/core_ext/class/attribute'
|
3
|
+
require 'active_support/concern'
|
4
|
+
require 'active_model'
|
5
|
+
|
6
|
+
module ActiveModel
|
7
|
+
module MassAssignmentSecurity
|
8
|
+
# Provides a patched version of the Sanitizer used in Rails to handle property
|
9
|
+
# and relationship objects as keys. There is no way to inject a custom sanitizer
|
10
|
+
# without reimplementing the permission sets.
|
11
|
+
Sanitizer.send(Sanitizer.is_a?(Module) ? :module_eval : :class_eval) do
|
12
|
+
# Returns all attributes not denied by the authorizer.
|
13
|
+
#
|
14
|
+
# @param [Hash{Symbol,String,::DataMapper::Property,::DataMapper::Relationship=>Object}] attributes
|
15
|
+
# Names and values of attributes to sanitize.
|
16
|
+
# @return [Hash]
|
17
|
+
# Sanitized hash of attributes.
|
18
|
+
def sanitize(attributes, authorizer = nil)
|
19
|
+
sanitized_attributes = attributes.reject do |key, value|
|
20
|
+
key_name = key.name rescue key
|
21
|
+
authorizer ? authorizer.deny?(key_name) : deny?(key_name)
|
22
|
+
end
|
23
|
+
debug_protected_attribute_removal(attributes, sanitized_attributes)
|
24
|
+
sanitized_attributes
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
module DataMapper
|
31
|
+
# Include this module into a DataMapper model to enable ActiveModel's mass
|
32
|
+
# assignment security.
|
33
|
+
#
|
34
|
+
# To use second parameter of {#attributes=} make sure to include this module
|
35
|
+
# last.
|
36
|
+
module MassAssignmentSecurity
|
37
|
+
extend ::ActiveSupport::Concern
|
38
|
+
include ::ActiveModel::MassAssignmentSecurity
|
39
|
+
|
40
|
+
module ClassMethods
|
41
|
+
extend ::ActiveModel::MassAssignmentSecurity::ClassMethods
|
42
|
+
|
43
|
+
def logger
|
44
|
+
@logger ||= ::DataMapper.logger
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Sanitizes the specified +attributes+ according to the defined mass-assignment
|
49
|
+
# security rules and calls +super+ with the result.
|
50
|
+
#
|
51
|
+
# Use either +attr_accessible+ to specify which attributes are allowed to be
|
52
|
+
# assigned via {#attributes=}, or +attr_protected+ to specify which attributes
|
53
|
+
# are *not* allowed to be assigned via {#attributes=}.
|
54
|
+
#
|
55
|
+
# +attr_accessible+ and +attr_protected+ are mutually exclusive.
|
56
|
+
#
|
57
|
+
# @param [Hash{Symbol,String,::DataMapper::Property,::DataMapper::Relationship=>Object}] attributes
|
58
|
+
# Names and values of attributes to sanitize.
|
59
|
+
# @param [Boolean] guard_protected_attributes
|
60
|
+
# Determines whether mass-security rules are applied (when +true+) or not.
|
61
|
+
# @return [Hash]
|
62
|
+
# Sanitized hash of attributes.
|
63
|
+
# @api public
|
64
|
+
#
|
65
|
+
# @example [Usage]
|
66
|
+
# class User
|
67
|
+
# include DataMapper::Resource
|
68
|
+
# include DataMapper::MassAssignmentSecurity
|
69
|
+
#
|
70
|
+
# property :name, String
|
71
|
+
# property :is_admin, Boolean
|
72
|
+
#
|
73
|
+
# # Only allow name to be set via #attributes=
|
74
|
+
# attr_accessible :name
|
75
|
+
# end
|
76
|
+
#
|
77
|
+
# user = User.new
|
78
|
+
# user.attributes = { :username => 'Phusion', :is_admin => true }
|
79
|
+
# user.username # => "Phusion"
|
80
|
+
# user.is_admin # => false
|
81
|
+
#
|
82
|
+
# user.send(:attributes=, { :username => 'Phusion', :is_admin => true }, false)
|
83
|
+
# user.is_admin # => true
|
84
|
+
def attributes=(attributes, guard_protected_attributes = true)
|
85
|
+
attributes = sanitize_for_mass_assignment(attributes) if guard_protected_attributes
|
86
|
+
super(attributes)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Rails
|
2
|
+
module DataMapper
|
3
|
+
module Middleware
|
4
|
+
|
5
|
+
class IdentityMap
|
6
|
+
def initialize(app, name = :default)
|
7
|
+
@app = app
|
8
|
+
@name = name.to_sym
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(env)
|
12
|
+
::DataMapper.repository(@name) do
|
13
|
+
@app.call(env)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
require 'active_support/core_ext/module/aliasing'
|
2
|
+
|
3
|
+
module Rails
|
4
|
+
module DataMapper
|
5
|
+
# Encapsulates an error of a multiparameter assignment.
|
6
|
+
class MultiparameterAssignmentError < StandardError
|
7
|
+
# Gets the target attribute of the assignment.
|
8
|
+
# @return [String]
|
9
|
+
attr_reader :attribute
|
10
|
+
|
11
|
+
# Gets the assigned values.
|
12
|
+
# @return [Array]
|
13
|
+
attr_reader :values
|
14
|
+
|
15
|
+
# Gets the exception raised on the assignment.
|
16
|
+
# @return [Exception]
|
17
|
+
attr_reader :exception
|
18
|
+
|
19
|
+
# Initializes a new instance of the {MultiparameterAssignmentError} class.
|
20
|
+
#
|
21
|
+
# @param [String] attribute The target attribute of the assignment.
|
22
|
+
# @param [Array] values The assigned values.
|
23
|
+
# @param [Exception] exception The exception raised on the assignment.
|
24
|
+
def initialize(attribute, values, exception)
|
25
|
+
super("Could not assign #{values.inspect} to #{attribute} (#{exception.message}).")
|
26
|
+
@attribute = attribute
|
27
|
+
@values = values
|
28
|
+
@exception = exception
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Raised by {MultiparameterAttributes#attributes=} when there are errors when
|
33
|
+
# merging multiparameter attributes. Use {#errors} to get the array of errors
|
34
|
+
# occured.
|
35
|
+
class MultiparameterAssignmentErrors < StandardError
|
36
|
+
# Gets the array of assignment errors.
|
37
|
+
# @return [Array<MultiparameterAssignmentError>]
|
38
|
+
attr_reader :errors
|
39
|
+
|
40
|
+
# Initializes a new instance of the {MultiparameterAssignmentErrors} class.
|
41
|
+
#
|
42
|
+
# @param [Array<MultiparameterAssignmentError>] errors
|
43
|
+
# The array of assignment errors.
|
44
|
+
# @param [String] message Optional error message.
|
45
|
+
def initialize(errors, message = nil)
|
46
|
+
super(message || "#{errors.size} error#{errors.size == 1 ? '' : 's'} on assignment of multiparameter attributes.")
|
47
|
+
@errors = errors
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Include this module into a DataMapper model to enable multiparameter
|
52
|
+
# attributes.
|
53
|
+
#
|
54
|
+
# A multiparameter attribute has +attr(Xc)+ as name where +attr+ specifies
|
55
|
+
# the attribute, +X+ the position of the value, and +c+ an optional typecast
|
56
|
+
# identifier. All values that share an +attr+ are sorted by their position,
|
57
|
+
# optionally cast using +#to_c+ (where +c+ is the typecast identifier) and
|
58
|
+
# then used to instantiate the proper attribute value.
|
59
|
+
#
|
60
|
+
# @example
|
61
|
+
# # Assigning a hash with multiparameter values for a +Date+ property called
|
62
|
+
# # +written_on+:
|
63
|
+
# resource.attributes = {
|
64
|
+
# 'written_on(1i)' => '2004',
|
65
|
+
# 'written_on(2i)' => '6',
|
66
|
+
# 'written_on(3i)' => '24' }
|
67
|
+
#
|
68
|
+
# # +Date+ will be initialized with each string cast to a number using
|
69
|
+
# # #to_i.
|
70
|
+
# resource.written_on == Date.new(2004, 6, 24)
|
71
|
+
module MultiparameterAttributes
|
72
|
+
# Merges multiparameter attributes and calls +super+ with the merged
|
73
|
+
# attributes.
|
74
|
+
#
|
75
|
+
# @param [Hash{String,Symbol=>Object}] attributes
|
76
|
+
# Names and values of attributes to assign.
|
77
|
+
# @return [Hash]
|
78
|
+
# Names and values of attributes assigned.
|
79
|
+
# @raise [MultiparameterAssignmentErrors]
|
80
|
+
# One or more multiparameters could not be assigned.
|
81
|
+
# @api public
|
82
|
+
def attributes=(attributes)
|
83
|
+
attribs = attributes.dup
|
84
|
+
multi_parameter_attributes = []
|
85
|
+
attribs.each do |k, v|
|
86
|
+
if k.to_s.include?("(")
|
87
|
+
multi_parameter_attributes << [ k, v ]
|
88
|
+
attribs.delete(k)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
attribs.merge!(merge_multiparameter_attributes(multi_parameter_attributes))
|
93
|
+
super(attribs)
|
94
|
+
end
|
95
|
+
|
96
|
+
protected
|
97
|
+
def merge_multiparameter_attributes(pairs)
|
98
|
+
pairs = extract_multiparameter_attributes(pairs)
|
99
|
+
|
100
|
+
errors = []
|
101
|
+
attributes = {}
|
102
|
+
pairs.each do |name, values_with_empty_parameters|
|
103
|
+
# ActiveRecord keeps the empty values to set dates without a year.
|
104
|
+
# Removing all nils (instead of removing only trailing nils) seems
|
105
|
+
# like a weird behavior though.
|
106
|
+
values = values_with_empty_parameters.compact
|
107
|
+
|
108
|
+
if values.empty?
|
109
|
+
attributes[name] = nil
|
110
|
+
next
|
111
|
+
end
|
112
|
+
|
113
|
+
klass = properties[name].primitive
|
114
|
+
begin
|
115
|
+
attributes[name] =
|
116
|
+
if klass == Time
|
117
|
+
Time.local(*values)
|
118
|
+
elsif klass == Date
|
119
|
+
# Date does not replace nil values with defaults.
|
120
|
+
Date.new(*values_with_empty_parameters.map { |v| v.nil? ? 1 : v })
|
121
|
+
else
|
122
|
+
klass.new(*values)
|
123
|
+
end
|
124
|
+
rescue => ex
|
125
|
+
errors << MultiparameterAssignmentError.new(name, values, ex)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
unless errors.empty?
|
130
|
+
raise MultiparameterAssignmentErrors.new(errors)
|
131
|
+
end
|
132
|
+
|
133
|
+
attributes
|
134
|
+
end
|
135
|
+
|
136
|
+
def extract_multiparameter_attributes(pairs)
|
137
|
+
attributes = {}
|
138
|
+
|
139
|
+
for multiparameter_name, value in pairs
|
140
|
+
unless multiparameter_name =~ /\A ([^\)]+) \( ([0-9]+) ([a-z])? \) \z/x
|
141
|
+
raise "Invalid multiparameter name #{multiparameter_name.inspect}."
|
142
|
+
end
|
143
|
+
|
144
|
+
name, position, typecast = $1, $2, $3
|
145
|
+
attributes[name] ||= []
|
146
|
+
|
147
|
+
parameter_value =
|
148
|
+
if value.empty?
|
149
|
+
nil
|
150
|
+
elsif typecast
|
151
|
+
value.send('to_' + typecast)
|
152
|
+
else
|
153
|
+
value
|
154
|
+
end
|
155
|
+
|
156
|
+
attributes[name] << [ position, parameter_value ]
|
157
|
+
end
|
158
|
+
|
159
|
+
# Order each parameter array according to the position, then discard the
|
160
|
+
# position.
|
161
|
+
attributes.each { |name, values|
|
162
|
+
attributes[name] = values.sort_by{ |v| v.first }.collect { |v| v.last }
|
163
|
+
}
|
164
|
+
end
|
165
|
+
end # MultiparameterAttributes
|
166
|
+
end
|
167
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'dm-core'
|
2
|
+
require 'dm-active_model'
|
3
|
+
|
4
|
+
require 'rails'
|
5
|
+
require 'active_model/railtie'
|
6
|
+
|
7
|
+
# Comment taken from active_record/railtie.rb
|
8
|
+
#
|
9
|
+
# For now, action_controller must always be present with
|
10
|
+
# rails, so let's make sure that it gets required before
|
11
|
+
# here. This is needed for correctly setting up the middleware.
|
12
|
+
# In the future, this might become an optional require.
|
13
|
+
require 'action_controller/railtie'
|
14
|
+
|
15
|
+
require 'dm-rails/setup'
|
16
|
+
require "dm-rails/railties/log_subscriber"
|
17
|
+
require "dm-rails/railties/i18n_support"
|
18
|
+
|
19
|
+
# The module provided in there is made available
|
20
|
+
# but users will still need to include it into the
|
21
|
+
# models they want it to use it in.
|
22
|
+
require 'dm-rails/mass_assignment_security'
|
23
|
+
require 'dm-rails/multiparameter_attributes'
|
24
|
+
|
25
|
+
module Rails
|
26
|
+
module DataMapper
|
27
|
+
|
28
|
+
class Railtie < Rails::Railtie
|
29
|
+
|
30
|
+
config.data_mapper = Rails::DataMapper::Configuration.create
|
31
|
+
|
32
|
+
config.app_generators.orm :data_mapper, :migration => true
|
33
|
+
|
34
|
+
|
35
|
+
# Support overwriting crucial steps in subclasses
|
36
|
+
|
37
|
+
def configure_data_mapper(app)
|
38
|
+
app.config.data_mapper.root = Rails.root
|
39
|
+
app.config.data_mapper.raw = app.config.database_configuration
|
40
|
+
end
|
41
|
+
|
42
|
+
def setup_i18n_support(app)
|
43
|
+
::DataMapper::Model.append_extensions(::ActiveModel::Translation)
|
44
|
+
::DataMapper::Model.append_extensions(Rails::DataMapper::I18nSupport)
|
45
|
+
end
|
46
|
+
|
47
|
+
def setup_controller_runtime(app)
|
48
|
+
require "dm-rails/railties/controller_runtime"
|
49
|
+
ActiveSupport.on_load(:action_controller) do
|
50
|
+
include Rails::DataMapper::Railties::ControllerRuntime
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def setup_logger(app, logger)
|
55
|
+
Rails::DataMapper.setup_logger(logger)
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
initializer 'data_mapper.configuration' do |app|
|
60
|
+
configure_data_mapper(app)
|
61
|
+
::DataMapper::Model.append_inclusions(Rails::DataMapper::MultiparameterAttributes)
|
62
|
+
end
|
63
|
+
|
64
|
+
initializer 'data_mapper.logger' do |app|
|
65
|
+
setup_logger(app, Rails.logger)
|
66
|
+
end
|
67
|
+
|
68
|
+
initializer 'data_mapper.i18n_support' do |app|
|
69
|
+
setup_i18n_support(app)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Expose database runtime to controller for logging.
|
73
|
+
initializer "data_mapper.log_runtime" do |app|
|
74
|
+
setup_controller_runtime(app)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Preload all models once in production mode,
|
78
|
+
# and before every request in development mode
|
79
|
+
initializer "datamapper.add_to_prepare" do |app|
|
80
|
+
config.to_prepare { Rails::DataMapper.preload_models(app) }
|
81
|
+
end
|
82
|
+
|
83
|
+
# Run setup code once in after_initialize to make sure all initializers
|
84
|
+
# are in effect once we setup the connection. Also, this will make sure
|
85
|
+
# that the connection gets set up after all models have been loaded,
|
86
|
+
# because #after_initialize is guaranteed to run after #to_prepare.
|
87
|
+
# Both production and development environment will execute the setup
|
88
|
+
# code only once.
|
89
|
+
config.after_initialize do |app|
|
90
|
+
Rails::DataMapper.setup(Rails.env)
|
91
|
+
end
|
92
|
+
|
93
|
+
rake_tasks do
|
94
|
+
load 'dm-rails/railties/database.rake'
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'active_support/core_ext/module/attr_internal'
|
2
|
+
|
3
|
+
module Rails
|
4
|
+
module DataMapper
|
5
|
+
module Railties
|
6
|
+
|
7
|
+
module ControllerRuntime
|
8
|
+
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
protected
|
12
|
+
|
13
|
+
attr_internal :db_runtime
|
14
|
+
|
15
|
+
def cleanup_view_runtime
|
16
|
+
# TODO add checks if DataMapper is connected to a repository.
|
17
|
+
# If it is, do this, if it isn't, just delegate to super
|
18
|
+
db_rt_before_render = ::DataMapper::Railties::LogSubscriber.reset_runtime
|
19
|
+
runtime = super
|
20
|
+
db_rt_after_render = ::DataMapper::Railties::LogSubscriber.reset_runtime
|
21
|
+
self.db_runtime = db_rt_before_render + db_rt_after_render
|
22
|
+
runtime - db_rt_after_render
|
23
|
+
end
|
24
|
+
|
25
|
+
def append_info_to_payload(payload)
|
26
|
+
super
|
27
|
+
payload[:db_runtime] = db_runtime
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
module ClassMethods
|
32
|
+
|
33
|
+
def log_process_action(payload)
|
34
|
+
messages, db_runtime = super, payload[:db_runtime]
|
35
|
+
messages << ("Models: %.3fms" % db_runtime.to_f) if db_runtime
|
36
|
+
messages
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'dm-rails/setup'
|
2
|
+
require 'dm-rails/storage'
|
3
|
+
|
4
|
+
namespace :db do
|
5
|
+
|
6
|
+
desc 'Create the database, load the schema, and initialize with the seed data'
|
7
|
+
task :setup => [ 'db:create', 'db:automigrate', 'db:seed' ]
|
8
|
+
|
9
|
+
namespace :create do
|
10
|
+
desc 'Create all the local databases defined in config/database.yml'
|
11
|
+
task :all => :environment do
|
12
|
+
Rails::DataMapper.storage.create_all
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
desc "Create all local databases defined for the current Rails.env"
|
17
|
+
task :create => :environment do
|
18
|
+
Rails::DataMapper.storage.create_environment(Rails::DataMapper.configuration.repositories[Rails.env])
|
19
|
+
end
|
20
|
+
|
21
|
+
namespace :drop do
|
22
|
+
desc 'Drop all the local databases defined in config/database.yml'
|
23
|
+
task :all => :environment do
|
24
|
+
Rails::DataMapper.storage.drop_all
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
desc "Drop all local databases defined for the current Rails.env"
|
29
|
+
task :drop => :environment do
|
30
|
+
Rails::DataMapper.storage.drop_environment(Rails::DataMapper.configuration.repositories[Rails.env])
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
desc 'Perform destructive automigration of all repositories in the current Rails.env'
|
35
|
+
task :automigrate => :environment do
|
36
|
+
require 'dm-migrations'
|
37
|
+
Rails::DataMapper.configuration.repositories[Rails.env].each do |repository, config|
|
38
|
+
::DataMapper.auto_migrate!(repository.to_sym)
|
39
|
+
puts "[datamapper] Finished auto_migrate! for :#{repository} repository '#{config['database']}'"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
desc 'Perform non destructive automigration of all repositories in the current Rails.env'
|
44
|
+
task :autoupgrade => :environment do
|
45
|
+
require 'dm-migrations'
|
46
|
+
Rails::DataMapper.configuration.repositories[Rails.env].each do |repository, config|
|
47
|
+
::DataMapper.auto_upgrade!(repository.to_sym)
|
48
|
+
puts "[datamapper] Finished auto_upgrade! for :#{repository} repository '#{config['database']}'"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
desc 'Load the seed data from db/seeds.rb'
|
53
|
+
task :seed => :environment do
|
54
|
+
seed_file = File.join(Rails.root, 'db', 'seeds.rb')
|
55
|
+
load(seed_file) if File.exist?(seed_file)
|
56
|
+
end
|
57
|
+
|
58
|
+
namespace :migrate do
|
59
|
+
task :load => :environment do
|
60
|
+
require 'dm-migrations/migration_runner'
|
61
|
+
FileList['db/migrate/*.rb'].each do |migration|
|
62
|
+
load migration
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
desc 'Migrate up using migrations'
|
67
|
+
task :up, [:version] => [:load] do |t, args|
|
68
|
+
::DataMapper::MigrationRunner.migrate_up!(args[:version])
|
69
|
+
end
|
70
|
+
|
71
|
+
desc 'Migrate down using migrations'
|
72
|
+
task :down, [:version] => [:load] do |t, args|
|
73
|
+
::DataMapper::MigrationRunner.migrate_down!(args[:version])
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
desc 'Migrate the database to the latest version'
|
78
|
+
task :migrate do
|
79
|
+
migrate_task = if Dir['db/migrate/*.rb'].empty?
|
80
|
+
'db:autoupgrade'
|
81
|
+
else
|
82
|
+
'db:migrate:up'
|
83
|
+
end
|
84
|
+
|
85
|
+
Rake::Task[migrate_task].invoke
|
86
|
+
end
|
87
|
+
|
88
|
+
namespace :sessions do
|
89
|
+
desc "Creates the sessions table for DataMapperStore"
|
90
|
+
task :create => :environment do
|
91
|
+
require 'dm-rails/session_store'
|
92
|
+
Rails::DataMapper::SessionStore::Session.auto_migrate!
|
93
|
+
database = Rails::DataMapper.configuration.repositories[Rails.env]['database']
|
94
|
+
puts "Created '#{database}.sessions'"
|
95
|
+
end
|
96
|
+
|
97
|
+
desc "Clear the sessions table for DataMapperStore"
|
98
|
+
task :clear => :environment do
|
99
|
+
require 'dm-rails/session_store'
|
100
|
+
Rails::DataMapper::SessionStore::Session.destroy!
|
101
|
+
database = Rails::DataMapper.configuration.repositories[Rails.env]['database']
|
102
|
+
puts "Deleted entries from '#{database}.sessions'"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'active_support/notifications'
|
2
|
+
|
3
|
+
# TODO This needs to be fixed upstream in active_support/notifications/instrumenter.rb
|
4
|
+
#
|
5
|
+
# We need to monkeypatch this for now, because the original implementation hardcodes the
|
6
|
+
# duration to the time elapsed between start and end of the event. The current upstream
|
7
|
+
# implementation is included here for reference:
|
8
|
+
#
|
9
|
+
# def duration
|
10
|
+
# @duration ||= 1000.0 * (@end - @time)
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# It should be safe to assume that explicitly provided duration information should be at
|
14
|
+
# least as precise as the current generic solution, if not more (as in our specific case).
|
15
|
+
#
|
16
|
+
module ActiveSupport
|
17
|
+
module Notifications
|
18
|
+
class Event
|
19
|
+
def duration
|
20
|
+
payload[:duration] ? (payload[:duration] / 1000.0) : 1000.0 * (self.end - self.time)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
module LogListener
|
27
|
+
def log(message)
|
28
|
+
ActiveSupport::Notifications.instrument('sql.data_mapper',
|
29
|
+
:name => 'SQL',
|
30
|
+
:sql => message.query, # TODO think about changing the key to :query
|
31
|
+
:start => message.start,
|
32
|
+
:duration => message.duration,
|
33
|
+
:connection_id => self.object_id
|
34
|
+
)
|
35
|
+
super
|
36
|
+
rescue Exception => e
|
37
|
+
::DataMapper.logger.error "[datamapper] #{e.class.name}: #{e.message}: #{message.inspect}}"
|
38
|
+
end
|
39
|
+
end
|