rails_devs_for_data_integrity 0.1.4 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG ADDED
@@ -0,0 +1,14 @@
1
+ 0.1.5 (2009-12-23)
2
+ * Changed: Il8n support for error messages
3
+ * Changed: Generate error messages for unique key violations based on the fields/columns derived from the mysql exception
4
+ * Changed: handle_unique_key_violation takes a scope parameter for unique keys across multiple columns
5
+ handle_unique_key_violation :field1, :scope => [:field2]
6
+
7
+ 0.1.4 (2009-12-17)
8
+ * Changed: handle_unique_key_violation can take several key arguments
9
+ handle_unique_key_violation :field1, :field2
10
+ * Changed: method to handle all violations by default: ActiveRecord::Base.enable_all_database_violation_checks
11
+
12
+ 0.1.3 (2009-12-16)
13
+ * Changed: Create a gem spec
14
+ * Fixed: Fix plugin to work with rails 2.0
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.4
1
+ 0.1.5
@@ -33,12 +33,19 @@ module ActiveRecord::RailsDevsForDataIntegrity
33
33
  def self.included(base)#:nodoc
34
34
  base.send :class_inheritable_hash, :unique_key_check_options
35
35
  base.send :class_inheritable_hash, :foreign_key_check_options
36
+ base.send :class_inheritable_hash, :default_violation_messages
37
+
36
38
  base.send :attr_reader, :duplicate_exception
37
39
  base.send :attr_reader, :foreign_key_exception
38
40
 
39
41
  base.unique_key_check_options = {}
40
42
  base.foreign_key_check_options = {}
41
-
43
+ base.default_violation_messages = {
44
+ :taken => 'has already been taken',
45
+ :taken_multiple => "has already been taken for {{context}}",
46
+ :taken_generic => 'Duplicate field.',
47
+ :foreign_key => "association does not exist."
48
+ }
42
49
  base.extend ClassMethods
43
50
  end
44
51
 
@@ -60,9 +67,12 @@ module ActiveRecord::RailsDevsForDataIntegrity
60
67
  alias_data_integrity_methods
61
68
  options = args.extract_options! || {}
62
69
  options.symbolize_keys!
63
-
64
70
  args.each do |name|
65
- self.unique_key_check_options[ name.to_sym ]= options.merge(:field_name => name)
71
+ self.unique_key_check_options[ name.to_sym ]= options.merge(
72
+ :field_name => name.to_s,
73
+ :columns => [name.to_s].
74
+ concat( (options[:scope]||[]).collect(&:to_s) ).uniq.sort
75
+ )
66
76
  end
67
77
  end
68
78
 
@@ -115,33 +125,78 @@ module ActiveRecord::RailsDevsForDataIntegrity
115
125
  end
116
126
  end
117
127
 
118
- # Add a duplicate error message to errors based on the exception
119
- def add_unique_key_error(exception)
120
- unless unique_key_check_options.blank?
121
- # we are not sure which violation occurred if we have multiple entries
122
- # since mysql does not return a good error message
123
- # add them all
124
- unique_key_check_options.each do |name, options|
125
- self.errors.add(options[:field_name], options[:message]||"has already been taken.")
126
- end
128
+ def default_error_message_for_violation( violation_type, columns )#:nodoc:
129
+ message_key = if violation_type == :foreign_key
130
+ :foreign_key
127
131
  else
128
- unique_key_check_options.keys
129
- self.errors.add_to_base(unique_key_check_options[:message]||"Duplicate field.")
132
+ case columns.length
133
+ when 0 then :taken_generic
134
+ when 1 then :taken
135
+ else :taken_multiple
136
+ end
130
137
  end
138
+ I18n.translate(
139
+ :"activerecord.errors.messages.#{message_key}",
140
+ :default => default_violation_messages[ message_key ],
141
+ :context => columns.slice(1..-1).join('/')
142
+ )
131
143
  end
132
144
 
133
- # Add a foreign key error message to errors based on the exception
134
- def add_foreign_key_error(exception, foreign_key=nil)
145
+ # Custom error messages set with handle_violation
146
+ def custom_error_message_for_violation( violation_type, columns )#:nodoc:
147
+ options = send(
148
+ "#{violation_type}_check_options"
149
+ )[ columns.first.to_sym ] if columns.any?
150
+
151
+ message = case options[:message]
152
+ when Symbol then Il8n.translate( options[:message] )
153
+ else options[:message]
154
+ end unless options.blank?
155
+ end
156
+
157
+ # Return the error message
158
+ def error_message_for_violation( violation_type, columns )#:nodoc:
159
+ message = custom_error_message_for_violation( violation_type, columns )
160
+ message ||= default_error_message_for_violation( violation_type, columns )
161
+ end
135
162
 
136
- foreign_key ||= foreign_key_from_error_message(exception)
137
- message = foreign_key_check_options[foreign_key.to_sym][:message] if foreign_key_check_options[foreign_key.to_sym]
138
- message ||= "association does not exist."
163
+ def add_errors_for_violation( violation_type, columns )
164
+ columns = [columns].flatten.compact
165
+ message = error_message_for_violation( violation_type, columns )
139
166
 
140
- if self.class.column_names.include?(foreign_key.to_s)
141
- self.errors.add(foreign_key, message)
167
+ if columns.blank?
168
+ self.errors.add_to_base( message )
142
169
  else
143
- self.errors.add_to_base(" #{foreign_key} #{message}")
170
+ self.errors.add( columns.first, message )
171
+ end
172
+ end
173
+
174
+ def index_for_record_not_unique(exception) #:nodoc:
175
+ case exception.message
176
+ when /Duplicate entry.*for key (\d+)/
177
+ index_position = $1.to_i
178
+ # minus two b/c mysql message is one-based + rails excludes primary key index from indexes list
179
+ ActiveRecord::Base.connection.indexes(self.class.table_name)[index_position - 2]
180
+ when /Duplicate entry.*for key '(\w+)'/
181
+ index_name = $1
182
+ ActiveRecord::Base.connection.indexes(self.class.table_name).detect { |i| i.name == index_name }
183
+ end
184
+ end
185
+
186
+
187
+ # Add a duplicate error message to errors based on the exception
188
+ def add_unique_key_error( exception, columns = nil )
189
+ columns ||= begin
190
+ index = index_for_record_not_unique( exception )
191
+ index.columns if index
144
192
  end
193
+ add_errors_for_violation( :unique_key, columns )
194
+ end
195
+
196
+ # Add a foreign key error message to errors based on the exception
197
+ def add_foreign_key_error(exception, foreign_key=nil)
198
+ foreign_key ||= foreign_key_from_error_message( exception )
199
+ add_errors_for_violation( :foreign_key, foreign_key )
145
200
  end
146
201
 
147
202
  # Return the foreign key name from the foreign key exception
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{rails_devs_for_data_integrity}
8
- s.version = "0.1.4"
8
+ s.version = "0.1.5"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Blythe Dunham"]
12
- s.date = %q{2009-12-17}
12
+ s.date = %q{2009-12-23}
13
13
  s.description = %q{Rails Devs For Data Integrity catches unique key and foreign key violations
14
14
  coming from the MySQLdatabase and converts them into an error on the
15
15
  ActiveRecord object similar to validation errors
@@ -20,6 +20,7 @@ Gem::Specification.new do |s|
20
20
  ]
21
21
  s.files = [
22
22
  ".gitignore",
23
+ "CHANGELOG",
23
24
  "MIT-LICENSE",
24
25
  "README",
25
26
  "Rakefile",
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_devs_for_data_integrity
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Blythe Dunham
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-12-17 00:00:00 -08:00
12
+ date: 2009-12-23 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -32,6 +32,7 @@ extra_rdoc_files:
32
32
  - README
33
33
  files:
34
34
  - .gitignore
35
+ - CHANGELOG
35
36
  - MIT-LICENSE
36
37
  - README
37
38
  - Rakefile