custom-attributes 0.2.17 → 0.2.18

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -1,8 +1,9 @@
1
1
  source :gemcutter
2
2
 
3
3
  # Rails 3.0
4
- gem 'rails', '3.0.0'
4
+ gem 'rails', '3.0.1'
5
5
  gem 'rspec', '2.0.0'
6
+ #gem 'validates_timeliness', '~> 3.0.0'
6
7
  gem 'sqlite3-ruby', :require => 'sqlite3'
7
8
  gem 'mysql'
8
9
  gem 'pg'
data/Gemfile.lock CHANGED
@@ -2,12 +2,12 @@ GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
4
  abstract (1.0.0)
5
- actionmailer (3.0.0)
6
- actionpack (= 3.0.0)
5
+ actionmailer (3.0.1)
6
+ actionpack (= 3.0.1)
7
7
  mail (~> 2.2.5)
8
- actionpack (3.0.0)
9
- activemodel (= 3.0.0)
10
- activesupport (= 3.0.0)
8
+ actionpack (3.0.1)
9
+ activemodel (= 3.0.1)
10
+ activesupport (= 3.0.1)
11
11
  builder (~> 2.1.2)
12
12
  erubis (~> 2.6.6)
13
13
  i18n (~> 0.4.1)
@@ -15,19 +15,19 @@ GEM
15
15
  rack-mount (~> 0.6.12)
16
16
  rack-test (~> 0.5.4)
17
17
  tzinfo (~> 0.3.23)
18
- activemodel (3.0.0)
19
- activesupport (= 3.0.0)
18
+ activemodel (3.0.1)
19
+ activesupport (= 3.0.1)
20
20
  builder (~> 2.1.2)
21
21
  i18n (~> 0.4.1)
22
- activerecord (3.0.0)
23
- activemodel (= 3.0.0)
24
- activesupport (= 3.0.0)
22
+ activerecord (3.0.1)
23
+ activemodel (= 3.0.1)
24
+ activesupport (= 3.0.1)
25
25
  arel (~> 1.0.0)
26
26
  tzinfo (~> 0.3.23)
27
- activeresource (3.0.0)
28
- activemodel (= 3.0.0)
29
- activesupport (= 3.0.0)
30
- activesupport (3.0.0)
27
+ activeresource (3.0.1)
28
+ activemodel (= 3.0.1)
29
+ activesupport (= 3.0.1)
30
+ activesupport (3.0.1)
31
31
  arel (1.0.1)
32
32
  activesupport (~> 3.0.0)
33
33
  builder (2.1.2)
@@ -59,17 +59,17 @@ GEM
59
59
  rack (>= 1.0.0)
60
60
  rack-test (0.5.6)
61
61
  rack (>= 1.0)
62
- rails (3.0.0)
63
- actionmailer (= 3.0.0)
64
- actionpack (= 3.0.0)
65
- activerecord (= 3.0.0)
66
- activeresource (= 3.0.0)
67
- activesupport (= 3.0.0)
62
+ rails (3.0.1)
63
+ actionmailer (= 3.0.1)
64
+ actionpack (= 3.0.1)
65
+ activerecord (= 3.0.1)
66
+ activeresource (= 3.0.1)
67
+ activesupport (= 3.0.1)
68
68
  bundler (~> 1.0.0)
69
- railties (= 3.0.0)
70
- railties (3.0.0)
71
- actionpack (= 3.0.0)
72
- activesupport (= 3.0.0)
69
+ railties (= 3.0.1)
70
+ railties (3.0.1)
71
+ actionpack (= 3.0.1)
72
+ activesupport (= 3.0.1)
73
73
  rake (>= 0.8.4)
74
74
  thor (~> 0.14.0)
75
75
  rake (0.8.7)
@@ -100,7 +100,7 @@ DEPENDENCIES
100
100
  jeweler
101
101
  mysql
102
102
  pg
103
- rails (= 3.0.0)
103
+ rails (= 3.0.1)
104
104
  rcov
105
105
  rspec (= 2.0.0)
106
106
  sqlite3-ruby
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.17
1
+ 0.2.18
@@ -21,14 +21,19 @@ module ActiveRecord
21
21
  field_definitions = CustomAttributeDefinitionHelper.new field_types
22
22
  yield field_definitions if block_given?
23
23
  defined_custom_attributes = field_definitions.defined_attributes
24
+ defined_custom_validations = field_definitions.defined_validations
24
25
 
25
26
  if has_custom_attributes?
26
27
  write_inheritable_attribute(:defined_custom_attributes, self.defined_custom_attributes.deep_merge(defined_custom_attributes))
28
+ write_inheritable_attribute(:defined_custom_validations, self.defined_custom_validations.deep_merge(defined_custom_validations))
27
29
  write_inheritable_attribute(:defined_custom_field_types, field_types)
28
30
  else
29
31
  write_inheritable_attribute(:defined_custom_attributes, defined_custom_attributes)
30
32
  class_inheritable_reader(:defined_custom_attributes)
31
33
 
34
+ write_inheritable_attribute(:defined_custom_validations, defined_custom_validations)
35
+ class_inheritable_reader(:defined_custom_validations)
36
+
32
37
  write_inheritable_attribute(:defined_custom_field_types, extra_field_types)
33
38
  class_inheritable_reader(:defined_custom_field_types)
34
39
 
@@ -48,6 +53,7 @@ module ActiveRecord
48
53
 
49
54
  def initialize extra_field_types
50
55
  @defined_attributes = {}
56
+ @defined_validations = {}
51
57
 
52
58
  extra_field_types.each do |key, value|
53
59
  class_eval do
@@ -64,12 +70,14 @@ module ActiveRecord
64
70
  end
65
71
  end
66
72
 
67
- attr_reader :defined_attributes
73
+ attr_reader :defined_attributes, :defined_validations
68
74
 
69
75
  private
70
76
 
71
77
  def define_field(type, *args)
72
78
  options = args.extract_options!
79
+ options.assert_valid_keys(:on_model, :validate_with, :validate_all_with)
80
+
73
81
  attributes_on_model = {}
74
82
  if options[:on_model].is_a? Array
75
83
  options[:on_model].each do |attribute|
@@ -78,13 +86,18 @@ module ActiveRecord
78
86
  elsif options[:on_model].is_a? Hash
79
87
  attributes_on_model = options[:on_model]
80
88
  end
89
+ if options[:validate_all_with]
90
+ @defined_validations[type] = options[:validate_all_with]
91
+ end
92
+
81
93
  args.each do |field|
82
94
  field = field.to_sym
83
95
  @defined_attributes[type] ||= {}
84
96
  @defined_attributes[type][field] = {
85
97
  :type => type,
86
98
  :name => field,
87
- :on_model => attributes_on_model[field] || false
99
+ :on_model => attributes_on_model[field] || false,
100
+ :validate_with => options[:validate_with] || nil
88
101
  }
89
102
  end
90
103
  end
@@ -101,6 +114,7 @@ module ActiveRecord
101
114
 
102
115
  base.before_save :cache_custom_attributes
103
116
  base.after_save :save_custom_attributes
117
+ base.validate :validate_custom_attributes
104
118
  end
105
119
 
106
120
  module ClassMethods
@@ -126,6 +140,11 @@ module ActiveRecord
126
140
  def save_custom_attributes
127
141
  custom_attributes.save
128
142
  end
143
+
144
+ def validate_custom_attributes
145
+ custom_attributes.validate(errors)
146
+ end
147
+
129
148
  end
130
149
 
131
150
  end
@@ -5,6 +5,7 @@ class ActiveRecord::CustomAttributes::CustomAttribute
5
5
  @item_list = item_list
6
6
  @attribute_model = attribute_model
7
7
  @marked_for_destruction = false
8
+ @errors = ActiveModel::Errors.new(self)
8
9
  load if @attribute_model
9
10
  end
10
11
 
@@ -30,23 +31,34 @@ class ActiveRecord::CustomAttributes::CustomAttribute
30
31
  @marked_for_destruction
31
32
  end
32
33
 
33
- def save
34
- attribute_model.destroy and return if marked_for_destruction?
35
-
36
- attribute_model.value_type = type.to_s
37
- attribute_model.field_name = internal_label.to_s
38
- attribute_model.field_label = label
39
- write_value = item_list.supported_attribute_types[type]
40
- field = FIELD_MAPPING[write_value]
34
+ def validate
35
+ errors.clear
36
+ return if marked_for_destruction?
37
+ assign_model_value
38
+ unless attribute_model.valid?
39
+ attribute_model.errors.each do |attribute, message|
40
+ errors.add :value, message
41
+ end
42
+ end
43
+ validations = item_list.get_custom_validations_for type, internal_label
44
+ validations.each do |validator|
45
+ main_model.send(validator, self) if validator.is_a? Symbol
46
+ validator.call(self) if validator.is_a? Proc
47
+ end
48
+ end
41
49
 
42
- converted_value = value
43
- converted_value = value ? 1 : 0 if write_value == :boolean
50
+ def valid?
51
+ errors.empty?
52
+ end
44
53
 
45
- ([:text, :date_time, :number, :float] - [field]).each { |value_field| attribute_model.send("#{value_field}_value=", nil) }
46
- attribute_model.send("#{field}_value=", value)
54
+ def save
55
+ attribute_model.destroy and return if marked_for_destruction?
56
+ assign_model_value
47
57
  attribute_model.save
48
58
  end
49
59
 
60
+ attr_reader :errors
61
+
50
62
  private
51
63
 
52
64
  attr_reader :main_model, :item_list
@@ -62,6 +74,20 @@ class ActiveRecord::CustomAttributes::CustomAttribute
62
74
  :time => :date_time
63
75
  }
64
76
 
77
+ def assign_model_value
78
+ attribute_model.value_type = type.to_s
79
+ attribute_model.field_name = internal_label.to_s
80
+ attribute_model.field_label = label
81
+ write_value = item_list.supported_attribute_types[type]
82
+ field = FIELD_MAPPING[write_value]
83
+
84
+ converted_value = value
85
+ converted_value = value ? 1 : 0 if write_value == :boolean
86
+
87
+ ([:text, :date_time, :number, :float] - [field]).each { |value_field| attribute_model.send("#{value_field}_value=", nil) }
88
+ attribute_model.send("#{field}_value=", converted_value)
89
+ end
90
+
65
91
  def load
66
92
  self.type = attribute_model.value_type.to_sym
67
93
  self.internal_label = attribute_model.field_name.to_sym
@@ -1,8 +1,9 @@
1
1
  class ActiveRecord::CustomAttributes::CustomAttributeList
2
2
 
3
3
  def initialize(record)
4
- @record = record
5
- @defined_attributes = @record.class.defined_custom_attributes
4
+ @record = record
5
+ @defined_attributes = @record.class.defined_custom_attributes
6
+ @defined_validations = @record.class.defined_custom_validations
6
7
  @extra_attribute_types = @record.class.defined_custom_field_types
7
8
  define_attribute_methods
8
9
  end
@@ -21,10 +22,10 @@ class ActiveRecord::CustomAttributes::CustomAttributeList
21
22
  end
22
23
 
23
24
  def add(type, label, value)
24
- type = type.to_sym
25
+ type = type.to_sym
25
26
  return if label.blank? and value.respond_to? :blank? and value.blank?
26
- internal_label = convert_to_internal_label(type, label)
27
- attribute = get_attribute(type, internal_label || label, true)
27
+ internal_label = convert_to_internal_label(type, label)
28
+ attribute = get_attribute(type, internal_label || label, true)
28
29
  attribute.value = value
29
30
  end
30
31
 
@@ -46,6 +47,21 @@ class ActiveRecord::CustomAttributes::CustomAttributeList
46
47
  loaded_attributes.each(&:save)
47
48
  end
48
49
 
50
+ def validate(errors)
51
+ loaded_attributes.each do |a|
52
+ a.validate
53
+ unless a.valid?
54
+ a.errors.each do |attribute, error_message|
55
+ errors.add(:custom_attributes, error_message)
56
+ end
57
+ end
58
+ end
59
+ end
60
+
61
+ def get_custom_validations_for(type, name)
62
+ [defined_validations[type], defined_attributes[type][name][:validate_with]].compact
63
+ end
64
+
49
65
  def defined_attribute_types
50
66
  (extra_attribute_types.keys + defined_attributes.keys).uniq
51
67
  end
@@ -60,14 +76,14 @@ class ActiveRecord::CustomAttributes::CustomAttributeList
60
76
 
61
77
  def supported_attribute_types
62
78
  return @supported_attribute_types if @supported_attribute_types
63
- standard_attribute_types = {}
79
+ standard_attribute_types = {}
64
80
  ActiveRecord::CustomAttributes::CUSTOM_ATTRIBUTE_TYPES.each { |t| standard_attribute_types[t.to_sym] = t.to_sym }
65
81
  @supported_attribute_types = (standard_attribute_types.merge extra_attribute_types)
66
82
  end
67
83
 
68
84
  def rename_label_of attribute, new_name
69
- internal_label = convert_to_internal_label(attribute.type, new_name)
70
- attribute.label = new_name
85
+ internal_label = convert_to_internal_label(attribute.type, new_name)
86
+ attribute.label = new_name
71
87
  attribute.internal_label = internal_label
72
88
  end
73
89
 
@@ -77,26 +93,26 @@ class ActiveRecord::CustomAttributes::CustomAttributeList
77
93
 
78
94
  private
79
95
 
80
- attr_reader :defined_attributes, :extra_attribute_types, :record
96
+ attr_reader :defined_attributes, :extra_attribute_types, :defined_validations, :record
81
97
 
82
98
  def get_attribute(type, internal_label, auto_create = false)
83
99
  if internal_label.is_a? Symbol
84
- attribute = loaded_attributes.find { |a| a.type == type and a.internal_label.to_s == internal_label.to_s }
100
+ attribute = loaded_attributes.find { |a| a.type == type and a.internal_label.to_s == internal_label.to_s }
85
101
  else
86
102
  attribute = loaded_attributes.find { |a| a.type == type and a.label == internal_label }
87
103
  end
88
104
  return attribute if attribute
89
105
  return nil unless auto_create
90
106
 
91
- new_attribute = ActiveRecord::CustomAttributes::CustomAttribute.new(self, record, nil)
107
+ new_attribute = ActiveRecord::CustomAttributes::CustomAttribute.new(self, record, nil)
92
108
  new_attribute.type = type.to_sym
93
109
 
94
110
  if internal_label.is_a? Symbol
95
111
  new_attribute.internal_label = internal_label
96
- new_attribute.label = human_label_for(type, internal_label)
112
+ new_attribute.label = human_label_for(type, internal_label)
97
113
  else
98
114
  new_attribute.internal_label = convert_to_internal_label(type, internal_label)
99
- new_attribute.label = internal_label
115
+ new_attribute.label = internal_label
100
116
  end
101
117
 
102
118
  loaded_attributes << new_attribute
@@ -112,7 +128,7 @@ class ActiveRecord::CustomAttributes::CustomAttributeList
112
128
 
113
129
  def human_label_for(type, internal_name)
114
130
  translate_scope = [:activerecord, :custom_attributes, record.class.name.underscore.to_sym, type.to_sym]
115
- defaults = [internal_name.to_s.underscore.gsub("_", " ").capitalize]
131
+ defaults = [internal_name.to_s.underscore.gsub("_", " ").capitalize]
116
132
  I18n.t(internal_name, :scope => translate_scope, :default => defaults)
117
133
  end
118
134
 
@@ -2,4 +2,12 @@ class ActiveRecord::CustomAttributes::CustomAttributeModel < ActiveRecord::Base
2
2
  set_table_name "custom_attributes"
3
3
 
4
4
  belongs_to :item, :polymorphic => true
5
+ validates :date_time_value, :presence => { :if => :date_storage? }
6
+
7
+ private
8
+
9
+ def date_storage?
10
+ ["date_time", "date", "time"].include? value_type
11
+ end
12
+
5
13
  end
@@ -1,19 +1,13 @@
1
1
  require File.expand_path('../../spec_helper', __FILE__)
2
2
 
3
3
  describe "Model without custom attributes" do
4
-
5
4
  subject { Location }
6
-
7
5
  it { should_not have_custom_attributes }
8
-
9
6
  end
10
7
 
11
8
  describe "Model with custom attributes" do
12
-
13
9
  subject { Person }
14
-
15
10
  it { should have_custom_attributes }
16
-
17
11
  end
18
12
 
19
13
  describe "Custom attributes of a person" do
@@ -21,11 +15,12 @@ describe "Custom attributes of a person" do
21
15
  clean_database!
22
16
 
23
17
  I18n.backend.store_translations :'nl', {
24
- :activerecord => {:custom_attributes => {:person => {:telephone => {:private => "Prive"}}}}
18
+ :activerecord => {:custom_attributes => {:person => {:telephone => {:private => "Prive"}}}},
19
+ :date => {:formats => {:default => "%d-%m-%Y"}}
25
20
  }
26
21
  I18n.default_locale = 'nl'
27
22
 
28
- @person = Person.new
23
+ @person = Person.new
29
24
  end
30
25
 
31
26
  subject { @person.custom_attributes }
@@ -51,7 +46,7 @@ describe "Custom attributes of a person" do
51
46
  @person.save
52
47
 
53
48
  loaded_person = Person.find @person.id
54
- fields = loaded_person.custom_attributes.telephone_attributes
49
+ fields = loaded_person.custom_attributes.telephone_attributes
55
50
  fields.should have(1).item
56
51
  fields[0].value.should == "06 28 61 06 28"
57
52
  end
@@ -86,7 +81,7 @@ describe "Custom attributes of a person" do
86
81
  it "should mark attributes for deletion" do
87
82
  @person.custom_attributes.add_telephone "Prive", "06 28 61 06 28"
88
83
 
89
- fields = @person.custom_attributes.telephone_attributes
84
+ fields = @person.custom_attributes.telephone_attributes
90
85
  fields.should have(1).item
91
86
  fields[0].mark_for_destruction
92
87
 
@@ -100,7 +95,7 @@ describe "Custom attributes of a person" do
100
95
  it "should accept post data in an custom_attributes hash" do
101
96
  # field format is #{@object.class.model_name.underscore}[custom_attributes][#{attribute_type}][#{field_type}][]
102
97
 
103
- custom_attribute_post_data = {
98
+ custom_attribute_post_data = {
104
99
  "telephone" => {
105
100
  "0" => {
106
101
  "label" => "Prive",
@@ -111,7 +106,7 @@ describe "Custom attributes of a person" do
111
106
  "value" => "1234567890"
112
107
  }
113
108
  },
114
- "email" => {
109
+ "email" => {
115
110
  "0" => {
116
111
  "label" => "Prive",
117
112
  "value" => "matthijs.groen@gmail.com"
@@ -119,9 +114,9 @@ describe "Custom attributes of a person" do
119
114
  }
120
115
  }
121
116
 
122
- @person.custom_attributes = custom_attribute_post_data
117
+ @person.custom_attributes = custom_attribute_post_data
123
118
 
124
- fields = @person.custom_attributes.telephone_attributes
119
+ fields = @person.custom_attributes.telephone_attributes
125
120
  fields.should have(2).items
126
121
  fields[0].value.should == "06 28 61 06 28"
127
122
  fields[1].value.should == "1234567890"
@@ -130,31 +125,63 @@ describe "Custom attributes of a person" do
130
125
  custom_attribute_second_post_data = {
131
126
  "telephone" => {
132
127
  "0" => {
133
- "label" => "Prive",
134
- "value" => "06 28 61 06 28",
128
+ "label" => "Prive",
129
+ "value" => "06 28 61 06 28",
135
130
  "_destroy" => true
136
131
  },
137
132
  "1" => {
138
- "label" => "Werk",
139
- "value" => "1234567890",
133
+ "label" => "Werk",
134
+ "value" => "1234567890",
140
135
  "_destroy" => "false"
141
136
  }
142
137
  },
143
- "email" => {
138
+ "email" => {
144
139
  "0" => {
145
140
  "label" => "Prive",
146
141
  "value" => "matthijs.groen@gmail.com"
147
142
  }
148
143
  }
149
144
  }
150
- @person.custom_attributes = custom_attribute_second_post_data
145
+ @person.custom_attributes = custom_attribute_second_post_data
151
146
 
152
- fields = @person.custom_attributes.telephone_attributes
147
+ fields = @person.custom_attributes.telephone_attributes
153
148
  fields.should have(1).items
154
149
  fields[0].value.should == "1234567890"
155
150
 
156
151
  end
157
152
 
153
+ it "should invalidate incorrect values" do
154
+ custom_attribute_invalid_post_data = {
155
+ "date" => {
156
+ "0" => {
157
+ "label" => "Born on",
158
+ "value" => "23422stufferror"
159
+
160
+ }
161
+ }
162
+ }
163
+ @person.custom_attributes = custom_attribute_invalid_post_data
164
+ @person.should_not be_valid
165
+
166
+ date_attributes = @person.custom_attributes.date_attributes
167
+ date_attributes.should have(1).items
168
+ date_attributes[0].should_not be_valid
169
+ end
170
+
171
+ it "should validate correct values" do
172
+ custom_attribute_valid_post_data = {
173
+ "date" => {
174
+ "0" => {
175
+ "label" => "Born on",
176
+ "value" => "31-05-1981"
177
+
178
+ }
179
+ }
180
+ }
181
+ @person.custom_attributes = custom_attribute_valid_post_data
182
+ @person.should be_valid
183
+ end
184
+
158
185
  end
159
186
 
160
187
  describe "Custom attributes of a product" do
@@ -199,4 +226,19 @@ describe "Custom attributes of a product" do
199
226
  @product.custom_attributes.size_value_of(:width).should == nil
200
227
  end
201
228
 
229
+ it "should run custom validations as method" do
230
+ @product.custom_attributes.add_size "Width", 16.3 # too large
231
+ @product.should_not be_valid
232
+ end
233
+
234
+ it "should run custom validations as lambda (value incorrect)" do
235
+ @product.custom_attributes.add_date "In stock since", Date.civil(2009, 12, 31)
236
+ @product.should_not be_valid
237
+ end
238
+
239
+ it "should run custom validations as lambda (value correct)" do
240
+ @product.custom_attributes.add_date "In stock since", Date.civil(2010, 1, 1)
241
+ @product.should be_valid
242
+ end
243
+
202
244
  end
data/spec/models.rb CHANGED
@@ -3,7 +3,11 @@ class Person < ActiveRecord::Base
3
3
  has_custom_attributes :telephone => :string, :email => :string do |fields|
4
4
  fields.telephone :work, :private, :mobile, :fax
5
5
  fields.email :work, :private
6
- fields.date :born_on, :wed_on, :died_on, :on_model => [ :born_on ]
6
+ fields.date :born_on, :wed_on, :died_on, :on_model => [:born_on]
7
+ end
8
+
9
+ def attribute_email(errors)
10
+
7
11
  end
8
12
 
9
13
  end
@@ -14,7 +18,13 @@ class Product < ActiveRecord::Base
14
18
 
15
19
  has_custom_attributes :size => :float do |fields|
16
20
  fields.size :width, :height, :depth
17
- fields.url :details, :on_model => { :details => :details_url }
21
+ fields.size :validate_all_with => :attribute_size_validation
22
+ fields.url :details, :on_model => {:details => :details_url}
23
+ fields.date :in_stock_since, :validate_with => lambda { |attribute| attribute.errors.add(:value, "must be after 2010") if attribute.value.to_date.year < 2010 }
24
+ end
25
+
26
+ def attribute_size_validation(attribute)
27
+ attribute.errors.add(:value, "should be between 1 and 10") if attribute.value < 1 or attribute.value > 10
18
28
  end
19
29
 
20
30
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: custom-attributes
3
3
  version: !ruby/object:Gem::Version
4
- hash: 53
4
+ hash: 51
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 2
9
- - 17
10
- version: 0.2.17
9
+ - 18
10
+ version: 0.2.18
11
11
  platform: ruby
12
12
  authors:
13
13
  - Matthijs Groen
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-10-20 00:00:00 +02:00
18
+ date: 2010-10-27 00:00:00 +02:00
19
19
  default_executable:
20
20
  dependencies: []
21
21
 
@@ -45,6 +45,7 @@ files:
45
45
  - lib/generators/custom_attributes/migration/migration_generator.rb
46
46
  - lib/generators/custom_attributes/migration/templates/active_record/migration.rb
47
47
  - rails/init.rb
48
+ - spec/custom_attributes/custom_attributes.sqlite3
48
49
  - spec/custom_attributes/has_custom_attributes_spec.rb
49
50
  - spec/database.yml
50
51
  - spec/database.yml.sample