redtape 0.0.8 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/redtape.rb CHANGED
@@ -1,40 +1,38 @@
1
1
  require "redtape/version"
2
+ require "redtape/attribute_whitelist"
3
+ require "redtape/model_factory"
4
+ require "redtape/populator/abstract"
5
+ require "redtape/populator/root"
6
+ require "redtape/populator/has_many"
7
+ require "redtape/populator/has_one"
2
8
 
3
9
  require 'active_model'
4
10
  require 'active_support/core_ext/class/attribute'
5
11
 
12
+ require 'active_record'
13
+
14
+ require 'forwardable'
15
+
6
16
  module Redtape
17
+
18
+ class DuelingBanjosError < StandardError; end
19
+ class WhitelistViolationError < StandardError; end
20
+
7
21
  class Form
22
+ extend Forwardable
8
23
  extend ActiveModel::Naming
24
+ include ActiveModel::Callbacks
9
25
  include ActiveModel::Conversion
10
26
  include ActiveModel::Validations
11
27
 
12
- validate :models_correct
13
- class_attribute :model_accessors
28
+ def_delegator :@factory, :model
14
29
 
15
- def self.validates_and_saves(*args)
16
- attr_accessor *args
17
- self.model_accessors = args
18
- end
19
-
20
- def initialize(attrs = {})
21
- attrs.each do |k, v|
22
- send("#{k}=", v)
30
+ def initialize(controller, args = {})
31
+ if controller.respond_to?(:populate_individual_record) && args[:whitelisted_attrs]
32
+ fail DuelingBanjosError, "Redtape::Form does not accept both #{controller.class}#populate_individual_record and the 'whitelisted_attrs' argument"
23
33
  end
24
- end
25
34
 
26
- def models_correct
27
- populate
28
- self.class.model_accessors.each do |accessor|
29
- begin
30
- model = send(accessor)
31
- if model.invalid?
32
- own_your_errors_in(model)
33
- end
34
- rescue NoMethodError => e
35
- fail NoMethodError, "#{self.class} is missing 'validates_and_saves :#{accessor}': #{e}"
36
- end
37
- end
35
+ @factory = ModelFactory.new(factory_args_for(controller, args))
38
36
  end
39
37
 
40
38
  # Forms are never themselves persisted
@@ -42,34 +40,38 @@ module Redtape
42
40
  false
43
41
  end
44
42
 
43
+ def valid?
44
+ model = @factory.populate_model
45
+ valid = model.valid?
46
+
47
+ # @errors comes from ActiveModel::Validations. This may not
48
+ # be a legit hook.
49
+ @errors = model.errors
50
+
51
+ valid
52
+ end
53
+
45
54
  def save
46
55
  if valid?
47
- persist!
56
+ begin
57
+ ActiveRecord::Base.transaction do
58
+ @factory.save!
59
+ end
60
+ rescue ActiveRecord::RecordInvalid
61
+ # This shouldn't even happen with the #valid? above.
62
+ end
48
63
  else
49
64
  false
50
65
  end
51
66
  end
52
67
 
53
- def persist!
54
- self.class.model_accessors.each do |accessor|
55
- model = send(accessor)
56
- unless model.save
57
- return false
58
- end
59
- end
60
- true
61
- end
62
-
63
- def populate
64
- fail NotImplementedError, "Implement #populate in your subclass"
65
- end
66
-
67
68
  private
68
69
 
69
- def own_your_errors_in(model)
70
- model.errors.each do |k, v|
71
- errors.add(k, v)
72
- end
70
+ def factory_args_for(controller, args)
71
+ args.dup.merge(
72
+ :attrs => controller.params,
73
+ :controller => controller
74
+ )
73
75
  end
74
76
  end
75
77
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redtape
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.8
4
+ version: 1.0.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-11-12 00:00:00.000000000 Z
12
+ date: 2012-11-30 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: virtus
@@ -27,6 +27,22 @@ dependencies:
27
27
  - - ! '>='
28
28
  - !ruby/object:Gem::Version
29
29
  version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rails
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
30
46
  - !ruby/object:Gem::Dependency
31
47
  name: rspec
32
48
  requirement: !ruby/object:Gem::Requirement
@@ -44,7 +60,7 @@ dependencies:
44
60
  - !ruby/object:Gem::Version
45
61
  version: '0'
46
62
  - !ruby/object:Gem::Dependency
47
- name: rails
63
+ name: sqlite3
48
64
  requirement: !ruby/object:Gem::Requirement
49
65
  none: false
50
66
  requirements:
@@ -60,7 +76,7 @@ dependencies:
60
76
  - !ruby/object:Gem::Version
61
77
  version: '0'
62
78
  - !ruby/object:Gem::Dependency
63
- name: debugger
79
+ name: pry
64
80
  requirement: !ruby/object:Gem::Requirement
65
81
  none: false
66
82
  requirements:
@@ -115,8 +131,6 @@ extensions: []
115
131
  extra_rdoc_files: []
116
132
  files:
117
133
  - lib/redtape.rb
118
- - lib/redtape/version.rb
119
- - spec/form_spec.rb
120
134
  homepage: http://github.com/ClearFit/redtape
121
135
  licenses: []
122
136
  post_install_message:
@@ -131,7 +145,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
131
145
  version: '0'
132
146
  segments:
133
147
  - 0
134
- hash: -1709053097785266848
148
+ hash: -2628988932070424880
135
149
  required_rubygems_version: !ruby/object:Gem::Requirement
136
150
  none: false
137
151
  requirements:
@@ -140,7 +154,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
140
154
  version: '0'
141
155
  segments:
142
156
  - 0
143
- hash: -1709053097785266848
157
+ hash: -2628988932070424880
144
158
  requirements: []
145
159
  rubyforge_project:
146
160
  rubygems_version: 1.8.24
@@ -150,5 +164,4 @@ summary: Redtape provides an alternative to [ActiveRecord::NestedAttributes#acce
150
164
  in the form of, well, a Form! The initial implementation was heavily inspired by
151
165
  ["7 Ways to Decompose Fat Activerecord Models"](http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/)
152
166
  by [Bryan Helmkamp](https://github.com/brynary).
153
- test_files:
154
- - spec/form_spec.rb
167
+ test_files: []
@@ -1,3 +0,0 @@
1
- module Redtape
2
- VERSION = "0.0.8"
3
- end
data/spec/form_spec.rb DELETED
@@ -1,134 +0,0 @@
1
- require 'virtus'
2
-
3
- require 'redtape'
4
- require 'active_model'
5
-
6
- class TestUser
7
- include Virtus
8
-
9
- extend ActiveModel::Naming
10
- include ActiveModel::Validations
11
- include ActiveModel::Conversion
12
-
13
- attribute :name, String
14
-
15
- validates_presence_of :name
16
- validate :name_contains_at_least_two_parts
17
-
18
- def name_contains_at_least_two_parts
19
- unless name =~ /.+ .+/
20
- errors.add(:name, "should contain at least two parts")
21
- end
22
- end
23
-
24
- def persisted?
25
- valid?
26
- end
27
-
28
- def save
29
- valid?
30
- end
31
- end
32
-
33
- class TestRegistrationForm < Redtape::Form
34
- validates_and_saves :test_user
35
-
36
- attr_accessor :test_user
37
-
38
- attr_accessor :first_name, :last_name
39
-
40
- def populate
41
- self.test_user = TestUser.new(:name => "#{first_name} #{last_name}")
42
- end
43
- end
44
-
45
- describe Redtape::Form do
46
- context "given a Form where the Form fields are a proper subset of the modeled fields" do
47
- context "where across all involved objects" do
48
- context "all field names are unique" do
49
- context "and the data is invalid" do
50
- context "in a root object" do
51
- it "reports an error on the model as <field_name>"
52
- end
53
- context "in a nested belongs_to/has_one" do
54
- it "reports an error on the model as <model_name>_<field_name>"
55
- end
56
- context "in a nested has_many" do
57
- it "reports an error on the model as <model_name>_<field_name>"
58
- end
59
- end
60
- end
61
-
62
- context "some field names overlap" do
63
- end
64
- end
65
- end
66
-
67
- context "given a Form accepting a first and last name that creates a User" do
68
- context "with valid data" do
69
- subject {
70
- TestRegistrationForm.new(
71
- :first_name => "Evan",
72
- :last_name => "Light"
73
- )
74
- }
75
-
76
- context "after saving the form" do
77
- before do
78
- subject.save
79
- end
80
-
81
- specify { subject.should be_valid }
82
- specify { subject.test_user.should be_valid }
83
- specify { subject.test_user.should be_persisted }
84
- end
85
-
86
- context "after validating the form" do
87
- before do
88
- subject.valid?
89
- end
90
-
91
- specify { subject.test_user.should be_valid }
92
- end
93
- end
94
-
95
- context "with invalid data" do
96
- subject {
97
- TestRegistrationForm.new.tap do |f|
98
- f.first_name = "Evan"
99
- end
100
- }
101
-
102
- context "after saving the form" do
103
- before do
104
- subject.save
105
- end
106
-
107
- specify { subject.should_not be_valid }
108
- specify { subject.should_not be_persisted }
109
- specify { subject.errors.should have_key(:name) }
110
- specify { subject.test_user.should_not be_valid }
111
- end
112
- end
113
- end
114
-
115
- context "given another Form subclass" do
116
- before do
117
- Class.new(Redtape::Form) do
118
- validates_and_saves :test_object
119
- end.new(:test_object => :foo)
120
- end
121
-
122
- subject {
123
- TestRegistrationForm.new
124
- }
125
-
126
- context "TestRegistrationForm still saves User" do
127
- before do
128
- subject.save
129
- end
130
-
131
- specify { subject.should_not be_valid }
132
- end
133
- end
134
- end