tpitale-dm-rails 1.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/.document +5 -0
- data/Gemfile +63 -0
- data/LICENSE +20 -0
- data/README.rdoc +595 -0
- data/Rakefile +27 -0
- data/VERSION +1 -0
- data/dm-rails.gemspec +94 -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 +77 -0
- data/lib/dm-rails/setup.rb +84 -0
- data/lib/dm-rails/storage.rb +209 -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/yard.rake +9 -0
- data/tasks/yardstick.rake +20 -0
- metadata +161 -0
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
gem 'jeweler', '~> 1.6.4'
|
6
|
+
require 'jeweler'
|
7
|
+
|
8
|
+
Jeweler::Tasks.new do |gem|
|
9
|
+
gem.name = 'dm-rails'
|
10
|
+
gem.summary = 'Use DataMapper with Rails 3'
|
11
|
+
gem.description = 'Integrate DataMapper with Rails 3'
|
12
|
+
gem.email = 'gamsnjaga@gmail.com'
|
13
|
+
gem.homepage = 'http://github.com/datamapper/%s' % gem.name
|
14
|
+
gem.authors = [ 'Martin Gamsjaeger (snusnu)', 'Dan Kubb' ]
|
15
|
+
|
16
|
+
gem.rubyforge_project = 'datamapper'
|
17
|
+
end
|
18
|
+
|
19
|
+
Jeweler::GemcutterTasks.new
|
20
|
+
|
21
|
+
FileList['tasks/**/*.rake'].each { |task| import task }
|
22
|
+
rescue LoadError
|
23
|
+
puts 'Jeweler (or a dependency) not available. Install it with: gem install jeweler'
|
24
|
+
end
|
25
|
+
|
26
|
+
require "spec/rake/spectask"
|
27
|
+
Spec::Rake::SpecTask.new
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.2.1
|
data/dm-rails.gemspec
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "tpitale-dm-rails"
|
8
|
+
s.version = "1.2.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Martin Gamsjaeger (snusnu)", "Dan Kubb"]
|
12
|
+
s.date = "2011-10-09"
|
13
|
+
s.description = "Integrate DataMapper with Rails 3"
|
14
|
+
s.email = "gamsnjaga@gmail.com"
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
"Gemfile",
|
22
|
+
"LICENSE",
|
23
|
+
"README.rdoc",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"dm-rails.gemspec",
|
27
|
+
"lib/dm-rails.rb",
|
28
|
+
"lib/dm-rails/configuration.rb",
|
29
|
+
"lib/dm-rails/mass_assignment_security.rb",
|
30
|
+
"lib/dm-rails/middleware/identity_map.rb",
|
31
|
+
"lib/dm-rails/multiparameter_attributes.rb",
|
32
|
+
"lib/dm-rails/railtie.rb",
|
33
|
+
"lib/dm-rails/railties/controller_runtime.rb",
|
34
|
+
"lib/dm-rails/railties/database.rake",
|
35
|
+
"lib/dm-rails/railties/i18n_support.rb",
|
36
|
+
"lib/dm-rails/railties/log_listener.rb",
|
37
|
+
"lib/dm-rails/railties/log_subscriber.rb",
|
38
|
+
"lib/dm-rails/session_store.rb",
|
39
|
+
"lib/dm-rails/setup.rb",
|
40
|
+
"lib/dm-rails/storage.rb",
|
41
|
+
"lib/generators/data_mapper.rb",
|
42
|
+
"lib/generators/data_mapper/migration/migration_generator.rb",
|
43
|
+
"lib/generators/data_mapper/migration/templates/migration.rb",
|
44
|
+
"lib/generators/data_mapper/model/model_generator.rb",
|
45
|
+
"lib/generators/data_mapper/model/templates/model.rb",
|
46
|
+
"lib/generators/data_mapper/observer/observer_generator.rb",
|
47
|
+
"lib/generators/data_mapper/observer/templates/observer.rb",
|
48
|
+
"spec/models/fake.rb",
|
49
|
+
"spec/models/topic.rb",
|
50
|
+
"spec/spec.opts",
|
51
|
+
"spec/spec_helper.rb",
|
52
|
+
"spec/unit/mass_assignment_security_spec.rb",
|
53
|
+
"spec/unit/multiparameter_attributes_spec.rb",
|
54
|
+
"tasks/clean.rake",
|
55
|
+
"tasks/yard.rake",
|
56
|
+
"tasks/yardstick.rake"
|
57
|
+
]
|
58
|
+
s.homepage = "http://github.com/datamapper/dm-rails"
|
59
|
+
s.require_paths = ["lib"]
|
60
|
+
s.rubyforge_project = "datamapper"
|
61
|
+
s.rubygems_version = "1.8.11"
|
62
|
+
s.summary = "Use DataMapper with Rails 3"
|
63
|
+
|
64
|
+
if s.respond_to? :specification_version then
|
65
|
+
s.specification_version = 3
|
66
|
+
|
67
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
68
|
+
s.add_runtime_dependency(%q<dm-core>, ["~> 1.2.0"])
|
69
|
+
s.add_runtime_dependency(%q<dm-active_model>, ["~> 1.2.0"])
|
70
|
+
s.add_runtime_dependency(%q<actionpack>, ["~> 3.1.0"])
|
71
|
+
s.add_runtime_dependency(%q<railties>, ["~> 3.1.0"])
|
72
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
|
73
|
+
s.add_development_dependency(%q<rake>, ["~> 0.9.2"])
|
74
|
+
s.add_development_dependency(%q<rspec>, ["~> 1.3.2"])
|
75
|
+
else
|
76
|
+
s.add_dependency(%q<dm-core>, ["~> 1.2.0"])
|
77
|
+
s.add_dependency(%q<dm-active_model>, ["~> 1.2.0"])
|
78
|
+
s.add_dependency(%q<actionpack>, ["~> 3.1.0"])
|
79
|
+
s.add_dependency(%q<railties>, ["~> 3.1.0"])
|
80
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
|
81
|
+
s.add_dependency(%q<rake>, ["~> 0.9.2"])
|
82
|
+
s.add_dependency(%q<rspec>, ["~> 1.3.2"])
|
83
|
+
end
|
84
|
+
else
|
85
|
+
s.add_dependency(%q<dm-core>, ["~> 1.2.0"])
|
86
|
+
s.add_dependency(%q<dm-active_model>, ["~> 1.2.0"])
|
87
|
+
s.add_dependency(%q<actionpack>, ["~> 3.1.0"])
|
88
|
+
s.add_dependency(%q<railties>, ["~> 3.1.0"])
|
89
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
|
90
|
+
s.add_dependency(%q<rake>, ["~> 0.9.2"])
|
91
|
+
s.add_dependency(%q<rspec>, ["~> 1.3.2"])
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
@@ -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
|
+
module Sanitizer
|
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)
|
19
|
+
sanitized_attributes = attributes.reject do |key, value|
|
20
|
+
key_name = key.name rescue key
|
21
|
+
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].dump_class
|
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
|