object_attorney 1.0.2 → 1.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/.gitignore +3 -2
- data/.rspec +3 -0
- data/.rvmrc +1 -0
- data/Gemfile +12 -0
- data/Guardfile +5 -0
- data/Rakefile +18 -0
- data/db/migrate/20131205114900_create_posts.rb +14 -0
- data/db/schema.rb +22 -0
- data/lib/object_attorney/nested_objects.rb +14 -6
- data/lib/object_attorney/orm.rb +21 -7
- data/lib/object_attorney/orm_handlers/smooth_operator.rb +6 -6
- data/lib/object_attorney/version.rb +1 -1
- data/lib/object_attorney.rb +24 -31
- data/object_attorney.gemspec +2 -2
- data/spec/object_attorney/bulk_posts_form_child_spec.rb +191 -0
- data/spec/object_attorney/bulk_posts_form_spec.rb +178 -0
- data/spec/object_attorney/post_form_child_spec.rb +60 -0
- data/spec/object_attorney/post_form_spec.rb +60 -0
- data/spec/spec_helper.rb +47 -0
- data/spec/support/active_model/validations.rb +21 -0
- data/spec/support/database_setup.rb +14 -0
- data/spec/support/models/bulk_posts_form.rb +21 -0
- data/spec/support/models/bulk_posts_form_child.rb +7 -0
- data/spec/support/models/post.rb +3 -0
- data/spec/support/models/post_form.rb +13 -0
- data/spec/support/models/post_form_child.rb +7 -0
- metadata +36 -7
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
YzdjZjUwYTk2MGM5NDM2Nzg3MTE4YmY3ODVhZDVlODQ4MmRiMmRjYg==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
NjQ0YzRjYjg3YTlkMzgyYTU5Njk4MTNmMTkwNDU2NWRiNWMxNmE2NQ==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
NTYwMTk5MGNjNzI4NTQwMWM4ZGFlOTBkY2JkMDYwZTdmZmQwMjk0ZGVjMDZl
|
10
|
+
NjIwZmUxNWY3ZThlNTViNTg5YjRiZjMwYTRiZDAyYTZmMGM5ZjJhYzg4ZGM5
|
11
|
+
YThhODIzOTFjMzAzMmE4YjM3MDgyMzhkNTlkOGRlYjlkODkwOWQ=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
MzQzNGRkZDIwMjYwOGVlMjFkMjkzYTA4MGM2OTQ5ZDk1OTdiNmQxZjE3MGM0
|
14
|
+
MTdmMGJmOWIzZGI2MzAwYWJmZTZhOGQ2YTM0MzczYmNlZWYzYzZlODUxYmU0
|
15
|
+
YjU4ODQ1MmYwZDkxMzk4MDBiNGViMWFhZGQyNWY2YWM1OTAyODQ=
|
data/.gitignore
CHANGED
data/.rspec
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm 1.9.3@object_attorney --create
|
data/Gemfile
CHANGED
@@ -2,3 +2,15 @@ source 'https://rubygems.org'
|
|
2
2
|
|
3
3
|
# Specify your gem's dependencies in object_attorney.gemspec
|
4
4
|
gemspec
|
5
|
+
|
6
|
+
group :development, :test do
|
7
|
+
gem "rspec", "~> 2.11"
|
8
|
+
gem "sqlite3"
|
9
|
+
gem "activerecord"
|
10
|
+
#gem 'database_cleaner'
|
11
|
+
gem "pry"
|
12
|
+
|
13
|
+
unless ENV["CI"]
|
14
|
+
gem "guard-rspec", "~> 0.7"
|
15
|
+
end
|
16
|
+
end
|
data/Guardfile
ADDED
data/Rakefile
CHANGED
@@ -1 +1,19 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
|
+
|
3
|
+
# see: http://blog.aizatto.com/2007/05/27/activerecord-migrations-without-rails/
|
4
|
+
# require 'active_record'
|
5
|
+
# require 'yaml'
|
6
|
+
|
7
|
+
# ENV["RAILS_ENV"] ||= 'test'
|
8
|
+
|
9
|
+
# task :default => :migrate
|
10
|
+
|
11
|
+
# desc "Migrate the database through scripts in db/migrate. Target specific version with VERSION=x"
|
12
|
+
# task :migrate => :environment do
|
13
|
+
# ActiveRecord::Migrator.migrate('db/migrate', ENV["VERSION"] ? ENV["VERSION"].to_i : nil )
|
14
|
+
# end
|
15
|
+
|
16
|
+
# task :environment do
|
17
|
+
# ActiveRecord::Base.establish_connection(YAML::load(File.open('config/database.yml'))[ENV["RAILS_ENV"]])
|
18
|
+
# ActiveRecord::Base.logger = Logger.new(File.open('tmp/database.log', 'a'))
|
19
|
+
# end
|
data/db/schema.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# This file is auto-generated from the current state of the database. Instead
|
2
|
+
# of editing this file, please use the migrations feature of Active Record to
|
3
|
+
# incrementally modify your database, and then regenerate this schema definition.
|
4
|
+
#
|
5
|
+
# Note that this schema.rb definition is the authoritative source for your
|
6
|
+
# database schema. If you need to create the application database on another
|
7
|
+
# system, you should be using db:schema:load, not running all the migrations
|
8
|
+
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
|
9
|
+
# you'll amass, the slower it'll run and the greater likelihood for issues).
|
10
|
+
#
|
11
|
+
# It's strongly recommended that you check this file into your version control system.
|
12
|
+
|
13
|
+
ActiveRecord::Schema.define(version: 20131020175047) do
|
14
|
+
|
15
|
+
create_table "posts", force: true do |t|
|
16
|
+
t.string "title"
|
17
|
+
t.text "body"
|
18
|
+
t.datetime "created_at"
|
19
|
+
t.datetime "updated_at"
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -2,7 +2,7 @@ module ObjectAttorney
|
|
2
2
|
module NestedObjects
|
3
3
|
|
4
4
|
def nested_objects
|
5
|
-
|
5
|
+
self.class.nested_objects.map { |nested_object_sym| self.send(nested_object_sym) }.flatten
|
6
6
|
end
|
7
7
|
|
8
8
|
def mark_for_destruction
|
@@ -18,11 +18,17 @@ module ObjectAttorney
|
|
18
18
|
|
19
19
|
_destroy = attributes["_destroy"] || attributes[:_destroy]
|
20
20
|
|
21
|
-
object.mark_for_destruction if ["true", "1"].include?(_destroy)
|
21
|
+
object.mark_for_destruction if ["true", "1", true].include?(_destroy)
|
22
22
|
end
|
23
23
|
|
24
24
|
protected #################### PROTECTED METHODS DOWN BELOW ######################
|
25
25
|
|
26
|
+
def save_nested_objects(save_method)
|
27
|
+
nested_objects.map do |nested_object|
|
28
|
+
call_save_or_destroy(nested_object, save_method)
|
29
|
+
end.all?
|
30
|
+
end
|
31
|
+
|
26
32
|
def validate_nested_objects
|
27
33
|
#nested_objects.all?(&:valid?) #will not validate all nested_objects
|
28
34
|
return true if nested_objects.reject(&:marked_for_destruction?).map(&:valid?).all?
|
@@ -31,7 +37,7 @@ module ObjectAttorney
|
|
31
37
|
end
|
32
38
|
|
33
39
|
def import_nested_objects_errors
|
34
|
-
|
40
|
+
self.class.nested_objects.map do |nested_object_sym|
|
35
41
|
|
36
42
|
[*self.send(nested_object_sym)].each do |nested_object|
|
37
43
|
nested_object.errors.full_messages.each { |message| self.errors.add(nested_object_sym, message) }
|
@@ -54,8 +60,6 @@ module ObjectAttorney
|
|
54
60
|
base.class_eval do
|
55
61
|
validate :validate_nested_objects
|
56
62
|
end
|
57
|
-
|
58
|
-
@@nested_objects = []
|
59
63
|
end
|
60
64
|
|
61
65
|
def attributes_without_destroy(attributes)
|
@@ -101,7 +105,7 @@ module ObjectAttorney
|
|
101
105
|
|
102
106
|
def build_new_nested_objects(existing_and_new_nested_objects, nested_object_name)
|
103
107
|
(send("#{nested_object_name}_attributes") || {}).values.each do |attributes|
|
104
|
-
next if attributes["id"].present?
|
108
|
+
next if attributes["id"].present? || attributes[:id].present?
|
105
109
|
|
106
110
|
new_nested_object = send("build_#{nested_object_name.to_s.singularize}", attributes_without_destroy(attributes))
|
107
111
|
mark_for_destruction_if_necessary(new_nested_object, attributes)
|
@@ -122,6 +126,10 @@ module ObjectAttorney
|
|
122
126
|
nil
|
123
127
|
end
|
124
128
|
|
129
|
+
def nested_objects
|
130
|
+
self.instance_variable_get("@nested_objects") || zuper_method('nested_objects') || []
|
131
|
+
end
|
132
|
+
|
125
133
|
private #################### PRIVATE METHODS DOWN BELOW ######################
|
126
134
|
|
127
135
|
def define_nested_objects_getter_methods(nested_objects_list)
|
data/lib/object_attorney/orm.rb
CHANGED
@@ -2,13 +2,17 @@ require "object_attorney/orm_handlers/smooth_operator"
|
|
2
2
|
|
3
3
|
module ObjectAttorney
|
4
4
|
module ORM
|
5
|
+
|
6
|
+
def id
|
7
|
+
represented_object.try(:id)
|
8
|
+
end
|
5
9
|
|
6
10
|
def new_record?
|
7
|
-
try_or_return(
|
11
|
+
try_or_return(represented_object, :new_record?, true)
|
8
12
|
end
|
9
13
|
|
10
14
|
def persisted?
|
11
|
-
try_or_return(
|
15
|
+
try_or_return(represented_object, :persisted?, false)
|
12
16
|
end
|
13
17
|
|
14
18
|
def save
|
@@ -23,13 +27,13 @@ module ObjectAttorney
|
|
23
27
|
end
|
24
28
|
|
25
29
|
def destroy
|
26
|
-
return true if
|
27
|
-
evoke_method_on_object(
|
30
|
+
return true if represented_object.blank?
|
31
|
+
evoke_method_on_object(represented_object, :destroy)
|
28
32
|
end
|
29
33
|
|
30
34
|
def call_save_or_destroy(object, save_method)
|
31
35
|
if object == self
|
32
|
-
|
36
|
+
represented_object.present? ? evoke_method_on_object(represented_object, save_method) : true
|
33
37
|
else
|
34
38
|
save_method = :destroy if check_if_marked_for_destruction?(object)
|
35
39
|
evoke_method_on_object(object, save_method)
|
@@ -42,8 +46,18 @@ module ObjectAttorney
|
|
42
46
|
def after_save; end
|
43
47
|
|
44
48
|
def save_after_validations(save_method)
|
45
|
-
|
46
|
-
|
49
|
+
submit(save_method)
|
50
|
+
end
|
51
|
+
|
52
|
+
def submit(save_method)
|
53
|
+
save_result = save_represented_object(save_method)
|
54
|
+
save_result = save_nested_objects(save_method) if save_result
|
55
|
+
save_result
|
56
|
+
end
|
57
|
+
|
58
|
+
def save_represented_object(save_method)
|
59
|
+
return true if represented_object.blank?
|
60
|
+
call_save_or_destroy(represented_object, save_method)
|
47
61
|
end
|
48
62
|
|
49
63
|
private #################### PRIVATE METHODS DOWN BELOW ######################
|
@@ -15,13 +15,13 @@ module ObjectAttorney
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def destroy(options = {})
|
18
|
-
return true if
|
19
|
-
evoke_method_on_object(
|
18
|
+
return true if represented_object.blank?
|
19
|
+
evoke_method_on_object(represented_object, :destroy, options)
|
20
20
|
end
|
21
21
|
|
22
22
|
def call_save_or_destroy(object, save_method, options = {})
|
23
|
-
if object == self || object ==
|
24
|
-
|
23
|
+
if object == self || object == represented_object
|
24
|
+
represented_object.present? ? evoke_method_on_object(represented_object, save_method, options) : true
|
25
25
|
else
|
26
26
|
save_method = :destroy if check_if_marked_for_destruction?(object)
|
27
27
|
evoke_method_on_object(object, save_method, options)
|
@@ -31,8 +31,8 @@ module ObjectAttorney
|
|
31
31
|
protected #################### PROTECTED METHODS DOWN BELOW ######################
|
32
32
|
|
33
33
|
def save_after_validations(save_method, options = {})
|
34
|
-
return true if
|
35
|
-
evoke_method_on_object(
|
34
|
+
return true if represented_object.blank?
|
35
|
+
evoke_method_on_object(represented_object, save_method, options).ok?
|
36
36
|
end
|
37
37
|
|
38
38
|
private #################### PRIVATE METHODS DOWN BELOW ######################
|
data/lib/object_attorney.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require "object_attorney/version"
|
2
2
|
require "object_attorney/nested_objects"
|
3
3
|
require "object_attorney/orm"
|
4
|
+
require 'active_record'
|
4
5
|
|
5
6
|
module ObjectAttorney
|
6
7
|
|
@@ -39,21 +40,21 @@ module ObjectAttorney
|
|
39
40
|
|
40
41
|
def allowed_attribute(attribute)
|
41
42
|
attribute = attribute.to_s
|
42
|
-
|
43
|
-
return false if !respond_to?("#{attribute}=") || self.class.black_list.include?(attribute)
|
44
|
-
return true if self.class.white_list.empty?
|
45
|
-
|
46
|
-
self.class.white_list.include?(attribute)
|
43
|
+
respond_to?("#{attribute}=")
|
47
44
|
end
|
48
45
|
|
49
46
|
def validate_represented_object
|
50
|
-
valid = override_validations? ? true : try_or_return(
|
47
|
+
valid = override_validations? ? true : try_or_return(represented_object, :valid?, true)
|
51
48
|
import_represented_object_errors unless valid
|
52
49
|
valid
|
53
50
|
end
|
54
51
|
|
55
52
|
def import_represented_object_errors
|
56
|
-
|
53
|
+
represented_object.errors.each { |key, value| self.errors.add(key, value) }
|
54
|
+
end
|
55
|
+
|
56
|
+
def represented_object
|
57
|
+
@represented_object ||= self.class.represented_object_class.try(:new)
|
57
58
|
end
|
58
59
|
|
59
60
|
private #################### PRIVATE METHODS DOWN BELOW ######################
|
@@ -87,36 +88,28 @@ module ObjectAttorney
|
|
87
88
|
|
88
89
|
module ClassMethods
|
89
90
|
|
90
|
-
def represents(
|
91
|
-
|
91
|
+
def represents(represented_object_name, represented_object_class = nil)
|
92
|
+
self.instance_variable_set("@represented_object_class", represented_object_class || represented_object_name.to_s.camelize.constantize)
|
92
93
|
|
93
|
-
define_method(
|
94
|
-
|
94
|
+
define_method(represented_object_name) do
|
95
|
+
represented_object
|
95
96
|
end
|
96
97
|
end
|
97
98
|
|
98
|
-
def
|
99
|
-
|
100
|
-
end
|
101
|
-
|
102
|
-
def delegate_propertiy(property, options)
|
103
|
-
delegate property, "#{property}=", options
|
104
|
-
end
|
105
|
-
|
106
|
-
def attr_white_list=(*white_list)
|
107
|
-
@@white_list = white_list.map(&:to_s)
|
99
|
+
def represented_object_class
|
100
|
+
self.instance_variable_get("@represented_object_class") || zuper_method('represented_object_class')
|
108
101
|
end
|
109
102
|
|
110
|
-
def
|
111
|
-
|
103
|
+
def zuper_method(method_name, *args)
|
104
|
+
self.superclass.send(method_name, *args) if self.superclass.respond_to?(method_name)
|
112
105
|
end
|
113
106
|
|
114
|
-
def
|
115
|
-
|
107
|
+
def delegate_properties(*properties, options)
|
108
|
+
properties.each { |property| delegate_property(property, options) }
|
116
109
|
end
|
117
110
|
|
118
|
-
def
|
119
|
-
|
111
|
+
def delegate_property(property, options)
|
112
|
+
delegate property, "#{property}=", options
|
120
113
|
end
|
121
114
|
|
122
115
|
def human_attribute_name(attribute_key_name, options = {})
|
@@ -130,19 +123,19 @@ module ObjectAttorney
|
|
130
123
|
|
131
124
|
translation = I18n.translate(defaults.shift, options.merge(default: defaults))
|
132
125
|
|
133
|
-
if translation == no_translation &&
|
134
|
-
translation =
|
126
|
+
if translation == no_translation && represented_object_class.respond_to?(:human_attribute_name)
|
127
|
+
translation = represented_object_class.human_attribute_name(attribute_key_name, options)
|
135
128
|
end
|
136
129
|
|
137
130
|
translation
|
138
131
|
end
|
139
132
|
|
140
133
|
def model_name
|
141
|
-
|
134
|
+
@_model_name ||= begin
|
142
135
|
namespace = self.parents.detect do |n|
|
143
136
|
n.respond_to?(:use_relative_model_naming?) && n.use_relative_model_naming?
|
144
137
|
end
|
145
|
-
ActiveModel::Name.new(
|
138
|
+
ActiveModel::Name.new(represented_object_class || self, namespace)
|
146
139
|
end
|
147
140
|
end
|
148
141
|
|
data/object_attorney.gemspec
CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.version = ObjectAttorney::VERSION
|
9
9
|
spec.authors = ["João Gonçalves"]
|
10
10
|
spec.email = ["goncalves.joao@gmail.com"]
|
11
|
-
spec.description = %q{Form Object
|
12
|
-
spec.summary = %q{This gem allows you to extract the code responsible for
|
11
|
+
spec.description = %q{Form Object pattern implementation for Rails}
|
12
|
+
spec.summary = %q{This gem allows you to extract the code responsible for 'validations', 'nested objects' and 'strong parameters' from your model onto a specific class for a specific use case.}
|
13
13
|
spec.homepage = "https://github.com/goncalvesjoao/object_attorney"
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
@@ -0,0 +1,191 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe BulkPostsFormChild do
|
4
|
+
|
5
|
+
it "Creating multiple Posts, with a tabless model 'BulkPostsFormChild' has if it had 'accepts_nested_attributes_for :posts'" do
|
6
|
+
params = {
|
7
|
+
bulk_post: {
|
8
|
+
admin: true,
|
9
|
+
posts_attributes: {
|
10
|
+
"0" => { state: "draft", title: "My title1" },
|
11
|
+
"1" => { state: "public", title: "My title2" }
|
12
|
+
}
|
13
|
+
}
|
14
|
+
}
|
15
|
+
|
16
|
+
bulk_posts_form_child = BulkPostsFormChild.new(params[:bulk_post])
|
17
|
+
bulk_posts_form_child.save
|
18
|
+
|
19
|
+
expect(Post.all.count).to(eq(2))
|
20
|
+
end
|
21
|
+
|
22
|
+
it "Trying to create multiple Posts, with the same title (testing the 'validates_nested_uniqueness')" do
|
23
|
+
params = {
|
24
|
+
bulk_post: {
|
25
|
+
admin: true,
|
26
|
+
posts_attributes: {
|
27
|
+
"0" => { state: "draft", title: "My title1" },
|
28
|
+
"1" => { state: "public", title: "My title1" }
|
29
|
+
}
|
30
|
+
}
|
31
|
+
}
|
32
|
+
|
33
|
+
bulk_posts_form = BulkPostsFormChild.new(params[:bulk_post])
|
34
|
+
bulk_posts_form.save
|
35
|
+
|
36
|
+
# TODO: Ensure that the nested objects remember their respective errors
|
37
|
+
# see: http://stackoverflow.com/questions/13879700/rails-model-valid-flusing-custom-errors-and-falsely-returning-true
|
38
|
+
|
39
|
+
expect(Post.all.count).to(eq(0))
|
40
|
+
end
|
41
|
+
|
42
|
+
it "Creating new Post and editing an existing one" do
|
43
|
+
params = {
|
44
|
+
bulk_post: {
|
45
|
+
admin: true,
|
46
|
+
posts_attributes: {
|
47
|
+
"0" => { id: 1, state: "draft", title: "Changed title" },
|
48
|
+
"1" => { state: "public", title: "My title2" }
|
49
|
+
}
|
50
|
+
}
|
51
|
+
}
|
52
|
+
|
53
|
+
existing_post = Post.create(title: "My title1")
|
54
|
+
BulkPostsFormChild.new(params[:bulk_post]).save
|
55
|
+
existing_post.reload
|
56
|
+
|
57
|
+
expect(Post.all.count).to(eq(2)) && expect(existing_post.title).to(eq('Changed title'))
|
58
|
+
end
|
59
|
+
|
60
|
+
it "Creating new Post and deleting an existing one" do
|
61
|
+
params = {
|
62
|
+
bulk_post: {
|
63
|
+
admin: true,
|
64
|
+
posts_attributes: {
|
65
|
+
"0" => { id: 1, state: "draft", title: "Changed title", _destroy: true },
|
66
|
+
"1" => { state: "public", title: "My title2" }
|
67
|
+
}
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
existing_post = Post.create(title: "My title1")
|
72
|
+
BulkPostsFormChild.new(params[:bulk_post]).save
|
73
|
+
|
74
|
+
expect(Post.all.count).to(eq(1)) && expect(Post.where(id: existing_post.id).present?).to(eq(false))
|
75
|
+
end
|
76
|
+
|
77
|
+
it "Trying to create multiple Posts, but one of them is invalid" do
|
78
|
+
params = {
|
79
|
+
bulk_post: {
|
80
|
+
admin: true,
|
81
|
+
posts_attributes: {
|
82
|
+
"0" => { title: "My title1" },
|
83
|
+
"1" => { state: "public", title: "My title2" }
|
84
|
+
}
|
85
|
+
}
|
86
|
+
}
|
87
|
+
|
88
|
+
BulkPostsFormChild.new(params[:bulk_post]).save
|
89
|
+
|
90
|
+
params = {
|
91
|
+
bulk_post: {
|
92
|
+
admin: true,
|
93
|
+
posts_attributes: {
|
94
|
+
"0" => { state: 'draft', title: "My title1" },
|
95
|
+
"1" => { state: "public" }
|
96
|
+
}
|
97
|
+
}
|
98
|
+
}
|
99
|
+
|
100
|
+
BulkPostsFormChild.new(params[:bulk_post]).save
|
101
|
+
|
102
|
+
expect(Post.all.count).to(eq(0))
|
103
|
+
end
|
104
|
+
|
105
|
+
it "Trying to create new Post and editing an existing one, but one of them is invalid" do
|
106
|
+
params = {
|
107
|
+
bulk_post: {
|
108
|
+
admin: true,
|
109
|
+
posts_attributes: {
|
110
|
+
"0" => { id: 1, title: "Changed title" },
|
111
|
+
"1" => { state: "public", title: "My title2" }
|
112
|
+
}
|
113
|
+
}
|
114
|
+
}
|
115
|
+
|
116
|
+
existing_post = Post.create(title: "My title1")
|
117
|
+
BulkPostsFormChild.new(params[:bulk_post]).save
|
118
|
+
existing_post.reload
|
119
|
+
|
120
|
+
expect(Post.all.count).to(eq(1)) && expect(existing_post.title).to(eq('My title1'))
|
121
|
+
|
122
|
+
params = {
|
123
|
+
bulk_post: {
|
124
|
+
admin: true,
|
125
|
+
posts_attributes: {
|
126
|
+
"0" => { id: 1, state: 'draft', title: "Changed title" },
|
127
|
+
"1" => { state: "public" }
|
128
|
+
}
|
129
|
+
}
|
130
|
+
}
|
131
|
+
|
132
|
+
BulkPostsFormChild.new(params[:bulk_post]).save
|
133
|
+
existing_post.reload
|
134
|
+
|
135
|
+
expect(Post.all.count).to(eq(1)) && expect(existing_post.title).to(eq('My title1'))
|
136
|
+
end
|
137
|
+
|
138
|
+
it "Trying to create new Post and deleting an existing one, but the new one is invalid" do
|
139
|
+
params = {
|
140
|
+
bulk_post: {
|
141
|
+
admin: true,
|
142
|
+
posts_attributes: {
|
143
|
+
"0" => { id: 1, state: "draft", title: "Changed title", _destroy: true },
|
144
|
+
"1" => { state: "public" }
|
145
|
+
}
|
146
|
+
}
|
147
|
+
}
|
148
|
+
|
149
|
+
existing_post = Post.create(title: "My title1")
|
150
|
+
BulkPostsFormChild.new(params[:bulk_post]).save
|
151
|
+
existing_post.reload
|
152
|
+
|
153
|
+
expect(Post.all.count).to(eq(1)) && expect(existing_post.title).to(eq('My title1'))
|
154
|
+
end
|
155
|
+
|
156
|
+
it "Trying to create new Post and deleting an existing one, the existing one is invalid but since it is marked for destruction, it should be deleted" do
|
157
|
+
params = {
|
158
|
+
bulk_post: {
|
159
|
+
admin: true,
|
160
|
+
posts_attributes: {
|
161
|
+
"0" => { id: 1, title: "Changed title", _destroy: true },
|
162
|
+
"1" => { state: "public", title: "My title2" }
|
163
|
+
}
|
164
|
+
}
|
165
|
+
}
|
166
|
+
|
167
|
+
existing_post = Post.create(title: "My title1")
|
168
|
+
bulk_posts_form_child = BulkPostsFormChild.new(params[:bulk_post])
|
169
|
+
bulk_posts_form_child.save
|
170
|
+
|
171
|
+
expect(Post.all.count).to(eq(1)) && expect(Post.where(id: existing_post.id).present?).to(eq(false))
|
172
|
+
end
|
173
|
+
|
174
|
+
it "Trying to create new Post and deleting an existing one, both of them are invalid, no changes should occur." do
|
175
|
+
params = {
|
176
|
+
bulk_post: {
|
177
|
+
admin: true,
|
178
|
+
posts_attributes: {
|
179
|
+
"0" => { id: 1, title: "Changed title", _destroy: true },
|
180
|
+
"1" => { state: "public" }
|
181
|
+
}
|
182
|
+
}
|
183
|
+
}
|
184
|
+
|
185
|
+
existing_post = Post.create(title: "My title1")
|
186
|
+
BulkPostsFormChild.new(params[:bulk_post]).save
|
187
|
+
|
188
|
+
expect(Post.all.count).to(eq(1)) && expect(existing_post.title).to(eq('My title1'))
|
189
|
+
end
|
190
|
+
|
191
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe BulkPostsForm do
|
4
|
+
|
5
|
+
it "Creating multiple Posts, with a tabless model 'BulkPostsForm' has if it had 'accepts_nested_attributes_for :posts'" do
|
6
|
+
params = {
|
7
|
+
bulk_post: {
|
8
|
+
posts_attributes: {
|
9
|
+
"0" => { state: "draft", title: "My title1" },
|
10
|
+
"1" => { state: "public", title: "My title2" }
|
11
|
+
}
|
12
|
+
}
|
13
|
+
}
|
14
|
+
|
15
|
+
BulkPostsForm.new(params[:bulk_post]).save
|
16
|
+
|
17
|
+
expect(Post.all.count).to(eq(2))
|
18
|
+
end
|
19
|
+
|
20
|
+
it "Creating multiple Posts, with the same title (testing the 'validates_nested_uniqueness')" do
|
21
|
+
params = {
|
22
|
+
bulk_post: {
|
23
|
+
posts_attributes: {
|
24
|
+
"0" => { state: "draft", title: "My title1" },
|
25
|
+
"1" => { state: "public", title: "My title1" }
|
26
|
+
}
|
27
|
+
}
|
28
|
+
}
|
29
|
+
|
30
|
+
bulk_posts_form = BulkPostsForm.new(params[:bulk_post])
|
31
|
+
bulk_posts_form.save
|
32
|
+
|
33
|
+
# TODO: Ensure that the nested objects remember their respective errors
|
34
|
+
# see: http://stackoverflow.com/questions/13879700/rails-model-valid-flusing-custom-errors-and-falsely-returning-true
|
35
|
+
|
36
|
+
expect(Post.all.count).to(eq(0))
|
37
|
+
end
|
38
|
+
|
39
|
+
it "Creating new Post and editing an existing one" do
|
40
|
+
params = {
|
41
|
+
bulk_post: {
|
42
|
+
posts_attributes: {
|
43
|
+
"0" => { id: 1, state: "draft", title: "Changed title" },
|
44
|
+
"1" => { state: "public", title: "My title2" }
|
45
|
+
}
|
46
|
+
}
|
47
|
+
}
|
48
|
+
|
49
|
+
existing_post = Post.create(title: "My title1")
|
50
|
+
BulkPostsForm.new(params[:bulk_post]).save
|
51
|
+
existing_post.reload
|
52
|
+
|
53
|
+
expect(Post.all.count).to(eq(2)) && expect(existing_post.title).to(eq('Changed title'))
|
54
|
+
end
|
55
|
+
|
56
|
+
it "Creating new Post and deleting an existing one" do
|
57
|
+
params = {
|
58
|
+
bulk_post: {
|
59
|
+
posts_attributes: {
|
60
|
+
"0" => { id: 1, state: "draft", title: "Changed title", _destroy: true },
|
61
|
+
"1" => { state: "public", title: "My title2" }
|
62
|
+
}
|
63
|
+
}
|
64
|
+
}
|
65
|
+
|
66
|
+
existing_post = Post.create(title: "My title1")
|
67
|
+
BulkPostsForm.new(params[:bulk_post]).save
|
68
|
+
|
69
|
+
expect(Post.all.count).to(eq(1)) && expect(Post.where(id: existing_post.id).present?).to(eq(false))
|
70
|
+
end
|
71
|
+
|
72
|
+
it "Trying to create multiple Posts, but one of them is invalid" do
|
73
|
+
params = {
|
74
|
+
bulk_post: {
|
75
|
+
posts_attributes: {
|
76
|
+
"0" => { title: "My title1" },
|
77
|
+
"1" => { state: "public", title: "My title2" }
|
78
|
+
}
|
79
|
+
}
|
80
|
+
}
|
81
|
+
|
82
|
+
BulkPostsForm.new(params[:bulk_post]).save
|
83
|
+
|
84
|
+
params = {
|
85
|
+
bulk_post: {
|
86
|
+
posts_attributes: {
|
87
|
+
"0" => { state: 'draft', title: "My title1" },
|
88
|
+
"1" => { state: "public" }
|
89
|
+
}
|
90
|
+
}
|
91
|
+
}
|
92
|
+
|
93
|
+
BulkPostsForm.new(params[:bulk_post]).save
|
94
|
+
|
95
|
+
expect(Post.all.count).to(eq(0))
|
96
|
+
end
|
97
|
+
|
98
|
+
it "Trying to create new Post and editing an existing one, but one of them is invalid" do
|
99
|
+
params = {
|
100
|
+
bulk_post: {
|
101
|
+
posts_attributes: {
|
102
|
+
"0" => { id: 1, title: "Changed title" },
|
103
|
+
"1" => { state: "public", title: "My title2" }
|
104
|
+
}
|
105
|
+
}
|
106
|
+
}
|
107
|
+
|
108
|
+
existing_post = Post.create(title: "My title1")
|
109
|
+
BulkPostsForm.new(params[:bulk_post]).save
|
110
|
+
existing_post.reload
|
111
|
+
|
112
|
+
expect(Post.all.count).to(eq(1)) && expect(existing_post.title).to(eq('My title1'))
|
113
|
+
|
114
|
+
params = {
|
115
|
+
bulk_post: {
|
116
|
+
posts_attributes: {
|
117
|
+
"0" => { id: 1, state: 'draft', title: "Changed title" },
|
118
|
+
"1" => { state: "public" }
|
119
|
+
}
|
120
|
+
}
|
121
|
+
}
|
122
|
+
|
123
|
+
BulkPostsForm.new(params[:bulk_post]).save
|
124
|
+
existing_post.reload
|
125
|
+
|
126
|
+
expect(Post.all.count).to(eq(1)) && expect(existing_post.title).to(eq('My title1'))
|
127
|
+
end
|
128
|
+
|
129
|
+
it "Trying to create new Post and deleting an existing one, but the new one is invalid" do
|
130
|
+
params = {
|
131
|
+
bulk_post: {
|
132
|
+
posts_attributes: {
|
133
|
+
"0" => { id: 1, state: "draft", title: "Changed title", _destroy: true },
|
134
|
+
"1" => { state: "public" }
|
135
|
+
}
|
136
|
+
}
|
137
|
+
}
|
138
|
+
|
139
|
+
existing_post = Post.create(title: "My title1")
|
140
|
+
BulkPostsForm.new(params[:bulk_post]).save
|
141
|
+
existing_post.reload
|
142
|
+
|
143
|
+
expect(Post.all.count).to(eq(1)) && expect(existing_post.title).to(eq('My title1'))
|
144
|
+
end
|
145
|
+
|
146
|
+
it "Trying to create new Post and deleting an existing one, the existing one is invalid but since it is marked for destruction, it should be deleted" do
|
147
|
+
params = {
|
148
|
+
bulk_post: {
|
149
|
+
posts_attributes: {
|
150
|
+
"0" => { id: 1, title: "Changed title", _destroy: true },
|
151
|
+
"1" => { state: "public", title: "My title2" }
|
152
|
+
}
|
153
|
+
}
|
154
|
+
}
|
155
|
+
|
156
|
+
existing_post = Post.create(title: "My title1")
|
157
|
+
BulkPostsForm.new(params[:bulk_post]).save
|
158
|
+
|
159
|
+
expect(Post.all.count).to(eq(1)) && expect(Post.where(id: existing_post.id).present?).to(eq(false))
|
160
|
+
end
|
161
|
+
|
162
|
+
it "Trying to create new Post and deleting an existing one, both of them are invalid, no changes should occur." do
|
163
|
+
params = {
|
164
|
+
bulk_post: {
|
165
|
+
posts_attributes: {
|
166
|
+
"0" => { id: 1, title: "Changed title", _destroy: true },
|
167
|
+
"1" => { state: "public" }
|
168
|
+
}
|
169
|
+
}
|
170
|
+
}
|
171
|
+
|
172
|
+
existing_post = Post.create(title: "My title1")
|
173
|
+
BulkPostsForm.new(params[:bulk_post]).save
|
174
|
+
|
175
|
+
expect(Post.all.count).to(eq(1)) && expect(existing_post.title).to(eq('My title1'))
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe PostFormChild do
|
4
|
+
|
5
|
+
it "PostFormChild becomes invalid when Post does and incorporates its errors" do
|
6
|
+
post = Post.new
|
7
|
+
post.should have(1).error_on(:title)
|
8
|
+
post.title = "My title"
|
9
|
+
post.should have(:no).errors_on(:title)
|
10
|
+
|
11
|
+
post_form = PostFormChild.new({ state: 'draft', date: Date.today })
|
12
|
+
post_form.should have(1).error_on(:title)
|
13
|
+
post_form.title = "My title"
|
14
|
+
post_form.should have(:no).errors_on(:title)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "PostFormChild may require the validations of fields that Post doesn't have" do
|
18
|
+
params = { post: { title: "My title" } }
|
19
|
+
|
20
|
+
post = Post.new(params[:post])
|
21
|
+
post.should have(:no).errors_on(:date)
|
22
|
+
|
23
|
+
post_form = PostFormChild.new(params[:post].merge(state: 'public'))
|
24
|
+
post_form.should have(1).error_on(:date)
|
25
|
+
post_form.date = Date.today
|
26
|
+
post_form.should have(:no).errors_on(:date)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "Post creation through PostFormChild" do
|
30
|
+
params = { post: { state: 'public', title: "My title", body: "My body", date: Date.today } }
|
31
|
+
post_form = PostFormChild.new(params[:post])
|
32
|
+
|
33
|
+
expect(post_form.save).to(eq(true)) && expect(post_form.post.persisted?).to(eq(true))
|
34
|
+
end
|
35
|
+
|
36
|
+
it "Post can't be created if PostFormChild isn't valid" do
|
37
|
+
params = { post: { state: 'public', title: "My title", body: "My body" } }
|
38
|
+
post_form = PostFormChild.new(params[:post])
|
39
|
+
|
40
|
+
expect(post_form.save).to(eq(false)) && expect(post_form.post.persisted?).to(eq(false))
|
41
|
+
end
|
42
|
+
|
43
|
+
it "Post can't be created if Post isn't valid" do
|
44
|
+
params = { post: { state: 'public', date: Date.today, body: "My body" } }
|
45
|
+
post_form = PostFormChild.new(params[:post])
|
46
|
+
|
47
|
+
expect(post_form.save).to(eq(false)) && expect(post_form.post.persisted?).to(eq(false))
|
48
|
+
end
|
49
|
+
|
50
|
+
it "PostFormChild won't allow weak params to be updated, unlike Post" do
|
51
|
+
params = { post: { title: 'My title', body: "My body", admin: true } }
|
52
|
+
|
53
|
+
post_form = PostFormChild.new(params[:post].merge({ state: 'public', date: Date.today }))
|
54
|
+
expect(post_form.save).to(eq(true)) && expect(post_form.post.admin).to(eq(false))
|
55
|
+
|
56
|
+
post = Post.new(params[:post])
|
57
|
+
expect(post.save).to(eq(true)) && expect(post.admin).to(eq(true))
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe PostForm do
|
4
|
+
|
5
|
+
it "PostForm becomes invalid when Post does and incorporates its errors" do
|
6
|
+
post = Post.new
|
7
|
+
post.should have(1).error_on(:title)
|
8
|
+
post.title = "My title"
|
9
|
+
post.should have(:no).errors_on(:title)
|
10
|
+
|
11
|
+
post_form = PostForm.new({ state: 'draft' })
|
12
|
+
post_form.should have(1).error_on(:title)
|
13
|
+
post_form.title = "My title"
|
14
|
+
post_form.should have(:no).errors_on(:title)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "PostForm may require the validations of fields that Post doesn't have" do
|
18
|
+
params = { post: { title: "My title" } }
|
19
|
+
|
20
|
+
post = Post.new(params[:post])
|
21
|
+
post.should have(:no).errors_on(:state)
|
22
|
+
|
23
|
+
post_form = PostForm.new(params[:post])
|
24
|
+
post_form.should have(1).error_on(:state)
|
25
|
+
post_form.state = "draft"
|
26
|
+
post_form.should have(:no).errors_on(:state)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "Post creation through PostForm" do
|
30
|
+
params = { post: { state: 'public', title: "My title", body: "My body" } }
|
31
|
+
post_form = PostForm.new(params[:post])
|
32
|
+
|
33
|
+
expect(post_form.save).to(eq(true)) && expect(post_form.post.persisted?).to(eq(true))
|
34
|
+
end
|
35
|
+
|
36
|
+
it "Post can't be created if PostForm isn't valid" do
|
37
|
+
params = { post: { title: "My title", body: "My body" } }
|
38
|
+
post_form = PostForm.new(params[:post])
|
39
|
+
|
40
|
+
expect(post_form.save).to(eq(false)) && expect(post_form.post.persisted?).to(eq(false))
|
41
|
+
end
|
42
|
+
|
43
|
+
it "Post can't be created if Post isn't valid" do
|
44
|
+
params = { post: { state: 'public', body: "My body" } }
|
45
|
+
post_form = PostForm.new(params[:post])
|
46
|
+
|
47
|
+
expect(post_form.save).to(eq(false)) && expect(post_form.post.persisted?).to(eq(false))
|
48
|
+
end
|
49
|
+
|
50
|
+
it "PostForm won't allow weak params to be updated, unlike Post" do
|
51
|
+
params = { post: { title: 'My title', body: "My body", admin: true } }
|
52
|
+
|
53
|
+
post_form = PostForm.new(params[:post].merge({ state: 'public' }))
|
54
|
+
expect(post_form.save).to(eq(true)) && expect(post_form.post.admin).to(eq(false))
|
55
|
+
|
56
|
+
post = Post.new(params[:post])
|
57
|
+
expect(post.save).to(eq(true)) && expect(post.admin).to(eq(true))
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
|
3
|
+
|
4
|
+
ENV["RAILS_ENV"] ||= 'test'
|
5
|
+
|
6
|
+
require 'bundler'
|
7
|
+
Bundler.setup
|
8
|
+
require 'rspec'
|
9
|
+
require 'pry'
|
10
|
+
#require 'database_cleaner'
|
11
|
+
|
12
|
+
require 'object_attorney'
|
13
|
+
require 'support/database_setup'
|
14
|
+
require 'support/active_model/validations'
|
15
|
+
require 'support/models/post'
|
16
|
+
require 'support/models/post_form'
|
17
|
+
require 'support/models/post_form_child'
|
18
|
+
require 'support/models/bulk_posts_form'
|
19
|
+
require 'support/models/bulk_posts_form_child'
|
20
|
+
|
21
|
+
RSpec.configure do |config|
|
22
|
+
|
23
|
+
I18n.enforce_available_locales = false
|
24
|
+
|
25
|
+
# see: http://iain.nl/testing-activerecord-in-isolation
|
26
|
+
config.around do |example|
|
27
|
+
ActiveRecord::Base.transaction do
|
28
|
+
example.run
|
29
|
+
raise ActiveRecord::Rollback
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# see: https://github.com/bmabey/database_cleaner#rspec-example
|
34
|
+
# config.before(:suite) do
|
35
|
+
# DatabaseCleaner.strategy = :transaction
|
36
|
+
# DatabaseCleaner.clean_with(:truncation)
|
37
|
+
# end
|
38
|
+
|
39
|
+
# config.before(:each) do
|
40
|
+
# DatabaseCleaner.start
|
41
|
+
# end
|
42
|
+
|
43
|
+
# config.after(:each) do
|
44
|
+
# DatabaseCleaner.clean
|
45
|
+
# end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
|
2
|
+
# see: http://iain.nl/testing-activerecord-in-isolation
|
3
|
+
module ActiveModel::Validations
|
4
|
+
# Extension to enhance `should have` on AR Model instances. Calls
|
5
|
+
# model.valid? in order to prepare the object's errors object.
|
6
|
+
#
|
7
|
+
# You can also use this to specify the content of the error messages.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
#
|
11
|
+
# model.should have(:no).errors_on(:attribute)
|
12
|
+
# model.should have(1).error_on(:attribute)
|
13
|
+
# model.should have(n).errors_on(:attribute)
|
14
|
+
#
|
15
|
+
# model.errors_on(:attribute).should include("can't be blank")
|
16
|
+
def errors_on(attribute)
|
17
|
+
self.valid?
|
18
|
+
[self.errors[attribute]].flatten.compact
|
19
|
+
end
|
20
|
+
alias :error_on :errors_on
|
21
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# see: http://iain.nl/testing-activerecord-in-isolation
|
2
|
+
ActiveRecord::Base.establish_connection adapter: "sqlite3", database: ":memory:"
|
3
|
+
ActiveRecord::Migrator.up "db/migrate"
|
4
|
+
|
5
|
+
# see: http://blog.aizatto.com/2007/05/27/activerecord-migrations-without-rails/
|
6
|
+
#ActiveRecord::Base.establish_connection(YAML::load(File.open('config/database.yml'))[ENV["RAILS_ENV"]])
|
7
|
+
#ActiveRecord::Base.logger = Logger.new(File.open('tmp/database.log', 'a'))
|
8
|
+
|
9
|
+
# config/database.yml
|
10
|
+
# test:
|
11
|
+
# adapter: sqlite3
|
12
|
+
# database: db/test.sqlite3
|
13
|
+
# pool: 5
|
14
|
+
# timeout: 5000
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'object_attorney/nested_uniqueness_validator'
|
2
|
+
|
3
|
+
class BulkPostsForm
|
4
|
+
|
5
|
+
include ObjectAttorney
|
6
|
+
|
7
|
+
accepts_nested_objects :posts
|
8
|
+
|
9
|
+
validates_nested_uniqueness :posts, uniq_value: :title
|
10
|
+
|
11
|
+
##################### BODY BELLOW THIS LINE ####################
|
12
|
+
|
13
|
+
def build_post(attributes = {}, post = nil)
|
14
|
+
PostForm.new(attributes, post)
|
15
|
+
end
|
16
|
+
|
17
|
+
def existing_posts
|
18
|
+
Post.all.map { |post| build_post({}, post) }
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: object_attorney
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- João Gonçalves
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-12-
|
11
|
+
date: 2013-12-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -38,7 +38,7 @@ dependencies:
|
|
38
38
|
- - ! '>='
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
-
description: Form Object
|
41
|
+
description: Form Object pattern implementation for Rails
|
42
42
|
email:
|
43
43
|
- goncalves.joao@gmail.com
|
44
44
|
executables: []
|
@@ -46,10 +46,15 @@ extensions: []
|
|
46
46
|
extra_rdoc_files: []
|
47
47
|
files:
|
48
48
|
- .gitignore
|
49
|
+
- .rspec
|
50
|
+
- .rvmrc
|
49
51
|
- Gemfile
|
52
|
+
- Guardfile
|
50
53
|
- LICENSE.txt
|
51
54
|
- README.md
|
52
55
|
- Rakefile
|
56
|
+
- db/migrate/20131205114900_create_posts.rb
|
57
|
+
- db/schema.rb
|
53
58
|
- lib/object_attorney.rb
|
54
59
|
- lib/object_attorney/nested_objects.rb
|
55
60
|
- lib/object_attorney/nested_uniqueness_validator.rb
|
@@ -57,6 +62,18 @@ files:
|
|
57
62
|
- lib/object_attorney/orm_handlers/smooth_operator.rb
|
58
63
|
- lib/object_attorney/version.rb
|
59
64
|
- object_attorney.gemspec
|
65
|
+
- spec/object_attorney/bulk_posts_form_child_spec.rb
|
66
|
+
- spec/object_attorney/bulk_posts_form_spec.rb
|
67
|
+
- spec/object_attorney/post_form_child_spec.rb
|
68
|
+
- spec/object_attorney/post_form_spec.rb
|
69
|
+
- spec/spec_helper.rb
|
70
|
+
- spec/support/active_model/validations.rb
|
71
|
+
- spec/support/database_setup.rb
|
72
|
+
- spec/support/models/bulk_posts_form.rb
|
73
|
+
- spec/support/models/bulk_posts_form_child.rb
|
74
|
+
- spec/support/models/post.rb
|
75
|
+
- spec/support/models/post_form.rb
|
76
|
+
- spec/support/models/post_form_child.rb
|
60
77
|
homepage: https://github.com/goncalvesjoao/object_attorney
|
61
78
|
licenses:
|
62
79
|
- MIT
|
@@ -80,7 +97,19 @@ rubyforge_project:
|
|
80
97
|
rubygems_version: 2.1.10
|
81
98
|
signing_key:
|
82
99
|
specification_version: 4
|
83
|
-
summary: This gem allows you to extract the code responsible for
|
84
|
-
|
85
|
-
|
86
|
-
|
100
|
+
summary: This gem allows you to extract the code responsible for 'validations', 'nested
|
101
|
+
objects' and 'strong parameters' from your model onto a specific class for a specific
|
102
|
+
use case.
|
103
|
+
test_files:
|
104
|
+
- spec/object_attorney/bulk_posts_form_child_spec.rb
|
105
|
+
- spec/object_attorney/bulk_posts_form_spec.rb
|
106
|
+
- spec/object_attorney/post_form_child_spec.rb
|
107
|
+
- spec/object_attorney/post_form_spec.rb
|
108
|
+
- spec/spec_helper.rb
|
109
|
+
- spec/support/active_model/validations.rb
|
110
|
+
- spec/support/database_setup.rb
|
111
|
+
- spec/support/models/bulk_posts_form.rb
|
112
|
+
- spec/support/models/bulk_posts_form_child.rb
|
113
|
+
- spec/support/models/post.rb
|
114
|
+
- spec/support/models/post_form.rb
|
115
|
+
- spec/support/models/post_form_child.rb
|