foreign_key_validation 1.0.0 → 1.0.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.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- ZjUwMTlkNzAzZDliZTUxOGViNzJmNDA4YTVhNGY5NzEzNjdlYzJkZg==
4
+ MTRkMDgxMDUxZmJiN2ViODhiNjc2MjlkMjkwNzU3NWE1NGYyNDMxMw==
5
5
  data.tar.gz: !binary |-
6
- OWJkZjlkM2I4NWIyYmY3Y2IyZDRjZDQ2NTk3MjBjZDQ0YzkyMjFmNw==
6
+ NWRmMDQzMmRkNTM4OTE5MGIzZTRmMjk3ODllMDU1ZmYyOGZjZTkyMw==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- OTBmZmRhZDZlZDI5MDc1ZWM3Y2ExOWMxODIzZmQ1YjI3YmFkZjJkYTg2OTI3
10
- NTYxNWNhZmJmOTAyYzI2NjhiNTY4ODYzYjdhNjIxM2JiZTEyNjhhNTI0ZTcx
11
- MDEwZDc5ZDc1ZWE2M2EyZDUxMmQyNDMxYTdkYzk0M2M3ZGFlMTQ=
9
+ M2NhODc1MzQ0NDEwNGMwZmU0MzRkN2E2ZWJjZDg5OTlhYzFkYzhlYWEyM2Yx
10
+ MTUwMTQ3ZWU3ZGM0OTIxNTZhZTQ1MTMyZTk5ZDUzOGI2NzhjZTA1Nzg0MTk2
11
+ NWNhNjQzYzllOTIwYWJlNGM1ODk1NjIwY2ZhZDc0YzczYjRiNmY=
12
12
  data.tar.gz: !binary |-
13
- MmVhODBlOWU0MzQxNTRhYjIyN2U4MGJhNjViZDUwNzc3MTIyNDljY2M2MGE3
14
- NjJjZjUwODEzNTJiMjM4ZGYwMTI2MTNmNWMwZmQ0YjhiY2FlMDVjOWM5OTFj
15
- YmMwM2ZkN2NkZjMxOTc1Y2VlZDBhOThjNmI1YzZkZTMzMDJjNTk=
13
+ ODBhMWQ2MmZiMmE2N2NkZDc3YmJmYjU2MGQwYjQzYTliNjg3NzBlMGJjMGIw
14
+ OGVjYjQ2YTk2ZDA1MzdmNzFkNDdiMTU0ODE1MWUwYzlkNmJiMGY4ZDI0YTUy
15
+ ZjFiMjRhNWNmMjc0N2Y0NDNiYjhhMjljYTkyM2ZkZDM1NzI4Yzg=
data/README.md CHANGED
@@ -3,6 +3,7 @@
3
3
  [![Coverage Status](https://coveralls.io/repos/marcusg/foreign_key_validation/badge.png?branch=master)](https://coveralls.io/r/marcusg/foreign_key_validation?branch=master)
4
4
  [![Code Climate](https://codeclimate.com/github/marcusg/foreign_key_validation/badges/gpa.svg)](https://codeclimate.com/github/marcusg/foreign_key_validation)
5
5
  [![Build Status](https://travis-ci.org/marcusg/foreign_key_validation.svg?branch=master)](https://travis-ci.org/marcusg/foreign_key_validation)
6
+ [![Gem Version](https://badge.fury.io/rb/foreign_key_validation.svg)](http://badge.fury.io/rb/foreign_key_validation)
6
7
 
7
8
  Protect your models by specifying a collection of relations that should be tested for consistency with a predefined column (e.g. `user_id`).This is useful when the column `user_id` is used in multiple models. We can check if the `user_id` of *model A* matches `user_id` of *model B* before saving the records - if the IDs are different, an error will be attached to the errors hash of checked model.
8
9
 
@@ -0,0 +1,40 @@
1
+ module ForeignKeyValidation
2
+
3
+ class Collector
4
+ attr_accessor :klass, :validate_against, :reflections, :reflection_names, :validate_against_key, :validate_with
5
+
6
+ DEFAULT_VALIDATE_AGAINST = :user
7
+
8
+ def initialize(opt={})
9
+ self.klass = opt[:klass]
10
+ self.validate_against = find_validate_against(opt[:on])
11
+ self.reflections = klass.reflect_on_all_associations(:belongs_to)
12
+ self.reflection_names = reflections.map(&:name).map(&:to_s)
13
+ self.validate_against_key = find_validate_against_key
14
+ self.validate_with = find_validate_with(opt[:with])
15
+ end
16
+
17
+ def check!
18
+ raise Errors::NoReleationFoundError.new(klass.name) if reflection_names.empty?
19
+ raise Errors::NoForeignKeyFoundError.new(validate_against, klass.table_name) unless reflection_names.include?(validate_against)
20
+ raise Errors::UnknownRelationError.new(validate_with) unless validate_with.all? {|k| reflection_names.include?(k)}
21
+ true
22
+ end
23
+
24
+ private
25
+
26
+ def find_validate_against(on)
27
+ (on || DEFAULT_VALIDATE_AGAINST).to_s
28
+ end
29
+
30
+ def find_validate_with(with)
31
+ ((Array(with).map(&:to_s) if with) || reflection_names).reject {|n| n == validate_against}
32
+ end
33
+
34
+ def find_validate_against_key
35
+ reflections.select {|r| r.name.to_s == validate_against}.first.try(:foreign_key)
36
+ end
37
+
38
+ end
39
+
40
+ end
@@ -0,0 +1,26 @@
1
+ module ForeignKeyValidation
2
+
3
+ class Filter
4
+ attr_accessor :collector
5
+
6
+ def initialize(collector)
7
+ self.collector = collector
8
+ end
9
+
10
+ def before_filter(&block)
11
+ collector.klass.send :define_method, filter_name do
12
+ self.instance_eval &block
13
+ end
14
+ collector.klass.send :private, filter_name.to_sym
15
+ collector.klass.send :before_validation, filter_name
16
+ end
17
+
18
+ private
19
+
20
+ def filter_name
21
+ "validate_foreign_keys_on_#{collector.validate_against}"
22
+ end
23
+
24
+ end
25
+
26
+ end
@@ -2,35 +2,19 @@ module ForeignKeyValidation
2
2
  module ModelExtension
3
3
  extend ActiveSupport::Concern
4
4
 
5
- included do
6
- private
7
- def validate_foreign_key(validate_against_key, reflection_name)
8
- return if send(reflection_name).try(validate_against_key).nil? or try(validate_against_key).nil?
9
-
10
- if send(reflection_name).send(validate_against_key) != send(validate_against_key)
11
- errors.add(validate_against_key, "#{validate_against_key} of #{reflection_name} does not match #{self.class.name.tableize} #{validate_against_key}.")
12
- end
13
- end
14
- end
15
-
16
5
  module ClassMethods
6
+
17
7
  def validate_foreign_keys(opt={})
18
8
  subclasses.map {|klass| klass.send(:validate_foreign_keys, opt)}
19
9
 
20
- validator = Validator.new(self, opt)
21
- validator.check
10
+ collector = Collector.new(opt.merge(klass: self))
11
+ collector.check!
22
12
 
23
- define_method validator.filter_method_name do
24
- validator.validate_with.each do |reflection_name|
25
- validate_foreign_key(validator.validate_against_key, reflection_name)
26
- end
13
+ Filter.new(collector).before_filter do
14
+ Validator.validate(validate_against_key: collector.validate_against_key, reflection_names: collector.validate_with, object: self)
27
15
  end
28
- private validator.filter_method_name.to_sym
29
-
30
- before_validation validator.filter_method_name
31
16
  end
17
+
32
18
  end
33
19
  end
34
20
  end
35
-
36
- ActiveRecord::Base.send :include, ForeignKeyValidation::ModelExtension
@@ -1,41 +1,17 @@
1
1
  module ForeignKeyValidation
2
2
 
3
3
  class Validator
4
- attr_accessor :klass, :validate_against, :reflections, :reflection_names, :validate_against_key, :validate_with
5
4
 
6
- DEFAULT_VALIDATE_AGAINST = :user
5
+ def self.validate(opt={})
6
+ validate_against_key, reflection_names, object = opt[:validate_against_key], opt[:reflection_names], opt[:object]
7
7
 
8
- def initialize(klass, opt={})
9
- self.klass = klass
10
- self.validate_against = find_validate_against(opt[:on])
11
- self.reflections = klass.reflect_on_all_associations(:belongs_to)
12
- self.reflection_names = reflections.map(&:name).map(&:to_s)
13
- self.validate_against_key = find_validate_against_key
14
- self.validate_with = find_validate_with(opt[:with])
15
- end
16
-
17
- def check
18
- raise Errors::NoReleationFoundError.new(klass.name) if reflection_names.empty?
19
- raise Errors::NoForeignKeyFoundError.new(validate_against, klass.table_name) unless reflection_names.include?(validate_against)
20
- raise Errors::UnknownRelationError.new(validate_with) unless validate_with.all? {|k| reflection_names.include?(k)}
21
- end
22
-
23
- def filter_method_name
24
- "validate_foreign_keys_on_#{validate_against}"
25
- end
26
-
27
- private
28
-
29
- def find_validate_against(opt_on)
30
- (opt_on || DEFAULT_VALIDATE_AGAINST).to_s
31
- end
32
-
33
- def find_validate_with(opt_with)
34
- ((Array(opt_with).map(&:to_s) if opt_with) || reflection_names).reject {|n| n == validate_against}
35
- end
8
+ reflection_names.each do |reflection_name|
9
+ next if object.send(reflection_name).try(validate_against_key).nil? or object.try(validate_against_key).nil?
36
10
 
37
- def find_validate_against_key
38
- reflections.select {|r| r.name.to_s == validate_against}.first.try(:foreign_key)
11
+ if object.send(reflection_name).send(validate_against_key) != object.send(validate_against_key)
12
+ object.errors.add(validate_against_key, "#{validate_against_key} of #{reflection_name} does not match #{object.class.name.tableize} #{validate_against_key}.")
13
+ end
14
+ end
39
15
  end
40
16
 
41
17
  end
@@ -1,3 +1,3 @@
1
1
  module ForeignKeyValidation
2
- VERSION = "1.0.0"
2
+ VERSION = "1.0.1"
3
3
  end
@@ -1,4 +1,8 @@
1
1
  require "foreign_key_validation/version"
2
2
  require "foreign_key_validation/errors"
3
+ require "foreign_key_validation/collector"
4
+ require "foreign_key_validation/filter"
3
5
  require "foreign_key_validation/validator"
4
6
  require "foreign_key_validation/model_extension"
7
+
8
+ ActiveRecord::Base.send :include, ForeignKeyValidation::ModelExtension
@@ -0,0 +1,69 @@
1
+ require 'spec_helper'
2
+
3
+ describe ForeignKeyValidation::ModelExtension do
4
+
5
+ let(:user) { User.create }
6
+ let(:other_user) { User.create }
7
+
8
+ context "with calling validation with custom attributes hash" do
9
+ before do
10
+ Comment.class_eval do
11
+ validate_foreign_keys on: :user, with: :issue # member is not in list - should be editable
12
+ end
13
+ end
14
+
15
+ let(:project) { Project.create user: user }
16
+ let(:other_project) { Project.create user: other_user }
17
+ let(:issue) { Issue.create user: user, project: project }
18
+ let(:other_issue) { Issue.create user: other_user, project: other_project }
19
+ let(:comment) { Comment.create user: user, issue: issue }
20
+ let(:manager) { Manager.create user: user }
21
+ let(:other_manager) { Manager.create user: User.create }
22
+
23
+ it "uses same user ids by default" do
24
+ expect(project.user_id).to eq(user.id)
25
+ expect(issue.user_id).to eq(user.id)
26
+ expect(comment.user_id).to eq(user.id)
27
+ expect(manager.user_id).to eq(user.id)
28
+ end
29
+
30
+ it "does not allow to rewrite issue id of comment" do
31
+ comment.issue_id = other_issue.id
32
+ comment.save
33
+ expect(comment.errors.messages.values.flatten).to include("user_id of issue does not match comments user_id.")
34
+ expect(comment.reload.issue_id).to_not eq(other_issue.id)
35
+ end
36
+
37
+ # NOTE: this is possible here because Issue model is not configured to check ids
38
+ # comment model can only check id against issue model if it is present
39
+ it "does allow to rewrite issue id of comment with random id" do
40
+ comment.issue_id = 42
41
+ comment.save
42
+ comment.reload
43
+ expect(comment.issue_id).to eq(42)
44
+ end
45
+
46
+ it "allow to rewrite member id of comment" do
47
+ comment.member_id = other_manager.id
48
+ comment.save
49
+ comment.reload
50
+ expect(comment.member_id).to eq(other_manager.id)
51
+ end
52
+
53
+ it "allow to rewrite user id of issue" do
54
+ issue.user_id = other_user.id
55
+ issue.save
56
+ issue.reload
57
+ expect(issue.user_id).to eq(other_user.id)
58
+ end
59
+
60
+ it "allow to rewrite user id of manager" do
61
+ manager.user_id = other_user.id
62
+ manager.save
63
+ manager.reload
64
+ expect(manager.user_id).to eq(other_user.id)
65
+ end
66
+
67
+ end
68
+
69
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ describe ForeignKeyValidation::ModelExtension do
4
+
5
+ let(:user) { User.create }
6
+ let(:other_user) { User.create }
7
+
8
+ context "with calling private methods from model" do
9
+ before { Issue.send :validate_foreign_keys }
10
+
11
+ let(:issue) { Issue.create }
12
+
13
+ it "does not allow to call private validate_foreign_keys_on_* methods" do
14
+ expect{issue.validate_foreign_keys_on_user}.to raise_exception(/private method `validate_foreign_keys_on_user' called/)
15
+ end
16
+ end
17
+
18
+ context "with calling validation and wrong attributes hash" do
19
+
20
+ it "raises error due to wrong :on key" do
21
+ expect{Idea.class_eval { validate_foreign_keys on: :not_existing }}.to raise_error("No foreign key for relation not_existing on ideas table!")
22
+ end
23
+
24
+ it "raises error due to not related :on key" do
25
+ expect{Project.class_eval { validate_foreign_keys on: :comment }}.to raise_error("No foreign key for relation comment on projects table!")
26
+ end
27
+
28
+ it "raises error due to wrong :with key" do
29
+ expect{Idea.class_eval { validate_foreign_keys with: :not_existing }}.to raise_error('Unknown relation in ["not_existing"]!')
30
+ end
31
+
32
+ end
33
+
34
+ context "with calling validation and missing relations" do
35
+
36
+ it "raises error due to no existing relations" do
37
+ expect{Dummy.class_eval { validate_foreign_keys }}.to raise_error("Can't find any belongs_to relations for Dummy class. Put validation call below association definitions!")
38
+ end
39
+
40
+ end
41
+
42
+ end
@@ -0,0 +1,63 @@
1
+ require 'spec_helper'
2
+
3
+ describe ForeignKeyValidation::ModelExtension do
4
+
5
+ let(:user) { User.create }
6
+ let(:other_user) { User.create }
7
+
8
+ context "with calling validation and missing foreign key on relation" do
9
+
10
+ before do
11
+ Issue.class_eval do
12
+ validate_foreign_keys
13
+ end
14
+ end
15
+
16
+ let(:project) { Project.create }
17
+ let(:other_project) { Project.create }
18
+ let(:issue) { Issue.create project: project, user: user }
19
+
20
+ it "allow to rewrite user id of issue" do
21
+ issue.user_id = other_user.id
22
+ issue.save
23
+ issue.reload
24
+ expect(issue.user_id).to eq(other_user.id)
25
+ end
26
+
27
+ it "allow to rewrite project id of issue" do
28
+ issue.project_id = other_project.id
29
+ issue.save
30
+ issue.reload
31
+ expect(issue.project_id).to eq(other_project.id)
32
+ end
33
+
34
+ end
35
+
36
+ context "with calling validation and missing foreign key on self" do
37
+
38
+ before do
39
+ Issue.class_eval do
40
+ validate_foreign_keys
41
+ end
42
+ end
43
+
44
+ let(:project) { Project.create user: user }
45
+ let(:issue) { Issue.create project: project }
46
+
47
+ it "does not allow to rewrite user id of issue" do
48
+ issue.user_id = other_user.id
49
+ issue.save
50
+ expect(issue.errors.messages.values.flatten).to include("user_id of project does not match issues user_id.")
51
+ expect(issue.reload.user_id).to_not eq(other_user.id)
52
+ end
53
+
54
+ it "does not allow to rewrite user id of issue with random id" do
55
+ issue.user_id = 42
56
+ issue.save
57
+ expect(issue.errors.messages.values.flatten).to include("user_id of project does not match issues user_id.")
58
+ expect(issue.reload.user_id).to_not eq(42)
59
+ end
60
+
61
+ end
62
+
63
+ end
@@ -0,0 +1,107 @@
1
+ require 'spec_helper'
2
+
3
+ describe ForeignKeyValidation::ModelExtension do
4
+
5
+ let(:user) { User.create }
6
+ let(:other_user) { User.create }
7
+
8
+ context "with calling validation" do
9
+ before do
10
+ Idea.send :validate_foreign_keys
11
+ Project.send :validate_foreign_keys
12
+ Issue.send :validate_foreign_keys
13
+ Comment.send :validate_foreign_keys
14
+ Member.send :validate_foreign_keys
15
+ end
16
+
17
+ let(:project) { Project.create user: user }
18
+ let(:other_project) { Project.create user: other_user }
19
+ let(:idea) { Idea.create user: user, project: project }
20
+ let(:issue) { Issue.create user: user, project: project }
21
+ let(:other_issue) { Issue.create user: other_user, project: other_project }
22
+ let(:comment) { Comment.create user: user, issue: issue }
23
+ let(:manager) { Manager.create user: user }
24
+ let(:other_manager) { Manager.create user: User.create }
25
+ let(:developer) { Developer.create user: user, boss: manager }
26
+
27
+ it "uses same user ids by default" do
28
+ expect(project.user_id).to eq(user.id)
29
+ expect(idea.user_id).to eq(user.id)
30
+ expect(issue.user_id).to eq(user.id)
31
+ expect(comment.user_id).to eq(user.id)
32
+ expect(manager.user_id).to eq(user.id)
33
+ expect(developer.user_id).to eq(user.id)
34
+ end
35
+
36
+ it "does not allow to rewrite user id of idea" do
37
+ idea.user_id = other_user.id
38
+ idea.save
39
+ expect(idea.errors.messages.values.flatten).to include("user_id of project does not match ideas user_id.")
40
+ expect(idea.reload.user_id).to_not eq(other_user.id)
41
+ end
42
+
43
+ it "does not allow to rewrite user id of idea with random id" do
44
+ idea.user_id = 42
45
+ idea.save
46
+ expect(idea.errors.messages.values.flatten).to include("user_id of project does not match ideas user_id.")
47
+ expect(idea.reload.user_id).to_not eq(42)
48
+ end
49
+
50
+ it "does not allow to rewrite project id of idea" do
51
+ idea.project_id = other_project.id
52
+ idea.save
53
+ expect(idea.errors.messages.values.flatten).to include("user_id of project does not match ideas user_id.")
54
+ expect(idea.reload.user_id).to_not eq(other_project.id)
55
+ end
56
+
57
+ it "does not allow to rewrite user id of issue" do
58
+ issue.user_id = other_user.id
59
+ issue.save
60
+ expect(issue.errors.messages.values.flatten).to include("user_id of project does not match issues user_id.")
61
+ expect(issue.reload.user_id).to_not eq(other_user.id)
62
+ end
63
+
64
+ it "does not allow to rewrite project id of issue" do
65
+ issue.project_id = other_project.id
66
+ issue.save
67
+ expect(issue.errors.messages.values.flatten).to include("user_id of project does not match issues user_id.")
68
+ expect(issue.reload.user_id).to_not eq(other_project.id)
69
+ end
70
+
71
+ it "does not allow to rewrite user id of comment" do
72
+ comment.user_id = other_user.id
73
+ comment.save
74
+ expect(comment.errors.messages.values.flatten).to include("user_id of issue does not match comments user_id.")
75
+ expect(comment.reload.user_id).to_not eq(other_user.id)
76
+ end
77
+
78
+ it "does not allow to rewrite issue id of comment" do
79
+ comment.issue_id = other_issue.id
80
+ comment.save
81
+ expect(comment.errors.messages.values.flatten).to include("user_id of issue does not match comments user_id.")
82
+ expect(comment.reload.user_id).to_not eq(other_issue.id)
83
+ end
84
+
85
+ it "does allow to rewrite user id of project" do
86
+ project.user_id = other_user.id
87
+ project.save
88
+ expect(project.errors).to be_empty
89
+ expect(project.reload.user_id).to eq(other_user.id)
90
+ end
91
+
92
+ it "does not allow to rewrite user id of developer" do
93
+ developer.user_id = other_user.id
94
+ developer.save
95
+ expect(developer.errors.messages.values.flatten).to include("user_id of boss does not match developers user_id.")
96
+ expect(developer.reload.user_id).to_not eq(other_user.id)
97
+ end
98
+
99
+ it "does not allow to rewrite boss id of developer" do
100
+ developer.custom_boss_id = other_manager.id
101
+ developer.save
102
+ expect(developer.errors.messages.values.flatten).to include("user_id of boss does not match developers user_id.")
103
+ expect(developer.reload.custom_boss_id).to_not eq(other_manager.id)
104
+ end
105
+
106
+ end
107
+ end
@@ -0,0 +1,82 @@
1
+ require 'spec_helper'
2
+
3
+ describe ForeignKeyValidation::ModelExtension do
4
+
5
+ # NOTE: it's important to not create the objects through relation (user.projects.create...)
6
+ # it looks like active_record is caching the classes - but we need to test different class configs
7
+
8
+ let(:user) { User.create }
9
+ let(:other_user) { User.create }
10
+
11
+ context "without calling validation" do
12
+
13
+ let(:project) { Project.create user: user }
14
+ let(:idea) { Idea.create user: user, project: project }
15
+ let(:issue) { Issue.create user: user, project: project }
16
+ let(:comment) { Comment.create user: user, issue: issue }
17
+ let(:manager) { Manager.create user: user }
18
+ let(:other_manager) { Manager.create user: User.create }
19
+ let(:developer) { Developer.create user: user, boss: manager }
20
+
21
+ it "uses same user ids by default" do
22
+ expect(project.user_id).to eq(user.id)
23
+ expect(idea.user_id).to eq(user.id)
24
+ expect(issue.user_id).to eq(user.id)
25
+ expect(comment.user_id).to eq(user.id)
26
+ expect(manager.user_id).to eq(user.id)
27
+ expect(developer.user_id).to eq(user.id)
28
+ end
29
+
30
+ it "allow to rewrite user id of idea with random id" do
31
+ idea.user_id = 42
32
+ idea.save
33
+ idea.reload
34
+ expect(idea.user_id).to eq(42)
35
+ end
36
+
37
+ it "allow to rewrite user id of idea" do
38
+ idea.user_id = other_user.id
39
+ idea.save
40
+ idea.reload
41
+ expect(idea.user_id).to eq(other_user.id)
42
+ end
43
+
44
+ it "allow to rewrite user id of project" do
45
+ project.user_id = other_user.id
46
+ project.save
47
+ project.reload
48
+ expect(project.user_id).to eq(other_user.id)
49
+ end
50
+
51
+ it "allow to rewrite user id of issue" do
52
+ issue.user_id = other_user.id
53
+ issue.save
54
+ issue.reload
55
+ expect(issue.user_id).to eq(other_user.id)
56
+ end
57
+
58
+ it "allow to rewrite user id of comment" do
59
+ comment.user_id = other_user.id
60
+ comment.save
61
+ comment.reload
62
+ expect(comment.user_id).to eq(other_user.id)
63
+ end
64
+
65
+ it "allow to rewrite user id of developer" do
66
+ developer.user_id = other_user.id
67
+ developer.save
68
+ developer.reload
69
+ expect(developer.user_id).to eq(other_user.id)
70
+ end
71
+
72
+ it "allow to rewrite boss id of developer" do
73
+ developer.custom_boss_id = other_user.id
74
+ developer.save
75
+ developer.reload
76
+ expect(developer.custom_boss_id).to eq(other_user.id)
77
+ end
78
+
79
+ end
80
+
81
+
82
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foreign_key_validation
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marcus Geißler
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-09-30 00:00:00.000000000 Z
11
+ date: 2014-10-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -161,11 +161,17 @@ files:
161
161
  - gemfiles/4.1.gemfile
162
162
  - gemfiles/4.2.gemfile
163
163
  - lib/foreign_key_validation.rb
164
+ - lib/foreign_key_validation/collector.rb
164
165
  - lib/foreign_key_validation/errors.rb
166
+ - lib/foreign_key_validation/filter.rb
165
167
  - lib/foreign_key_validation/model_extension.rb
166
168
  - lib/foreign_key_validation/validator.rb
167
169
  - lib/foreign_key_validation/version.rb
168
- - spec/models/model_spec.rb
170
+ - spec/models/validation_with_custom_attrs_spec.rb
171
+ - spec/models/validation_with_exceptions_spec.rb
172
+ - spec/models/validation_with_missing_foreign_key_spec.rb
173
+ - spec/models/validation_without_attrs_spec.rb
174
+ - spec/models/without_validation_spec.rb
169
175
  - spec/spec_helper.rb
170
176
  - spec/support/load_models.rb
171
177
  - spec/support/reset_models.rb
@@ -195,7 +201,11 @@ signing_key:
195
201
  specification_version: 4
196
202
  summary: Protect the foreign keys in your Rails models.
197
203
  test_files:
198
- - spec/models/model_spec.rb
204
+ - spec/models/validation_with_custom_attrs_spec.rb
205
+ - spec/models/validation_with_exceptions_spec.rb
206
+ - spec/models/validation_with_missing_foreign_key_spec.rb
207
+ - spec/models/validation_without_attrs_spec.rb
208
+ - spec/models/without_validation_spec.rb
199
209
  - spec/spec_helper.rb
200
210
  - spec/support/load_models.rb
201
211
  - spec/support/reset_models.rb
@@ -1,337 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe ForeignKeyValidation::ModelExtension do
4
-
5
- # NOTE: it's important to not create the objects through relation (user.projects.create...)
6
- # it looks like active_record is caching the classes - but we need to test different class configs
7
-
8
- let(:user) { User.create }
9
- let(:other_user) { User.create }
10
-
11
- context "without calling validation" do
12
-
13
- let(:project) { Project.create user: user }
14
- let(:idea) { Idea.create user: user, project: project }
15
- let(:issue) { Issue.create user: user, project: project }
16
- let(:comment) { Comment.create user: user, issue: issue }
17
- let(:manager) { Manager.create user: user }
18
- let(:other_manager) { Manager.create user: User.create }
19
- let(:developer) { Developer.create user: user, boss: manager }
20
-
21
- it "uses same user ids by default" do
22
- expect(project.user_id).to eq(user.id)
23
- expect(idea.user_id).to eq(user.id)
24
- expect(issue.user_id).to eq(user.id)
25
- expect(comment.user_id).to eq(user.id)
26
- expect(manager.user_id).to eq(user.id)
27
- expect(developer.user_id).to eq(user.id)
28
- end
29
-
30
- it "allow to rewrite user id of idea with random id" do
31
- idea.user_id = 42
32
- idea.save
33
- idea.reload
34
- expect(idea.user_id).to eq(42)
35
- end
36
-
37
- it "allow to rewrite user id of idea" do
38
- idea.user_id = other_user.id
39
- idea.save
40
- idea.reload
41
- expect(idea.user_id).to eq(other_user.id)
42
- end
43
-
44
- it "allow to rewrite user id of project" do
45
- project.user_id = other_user.id
46
- project.save
47
- project.reload
48
- expect(project.user_id).to eq(other_user.id)
49
- end
50
-
51
- it "allow to rewrite user id of issue" do
52
- issue.user_id = other_user.id
53
- issue.save
54
- issue.reload
55
- expect(issue.user_id).to eq(other_user.id)
56
- end
57
-
58
- it "allow to rewrite user id of comment" do
59
- comment.user_id = other_user.id
60
- comment.save
61
- comment.reload
62
- expect(comment.user_id).to eq(other_user.id)
63
- end
64
-
65
- it "allow to rewrite user id of developer" do
66
- developer.user_id = other_user.id
67
- developer.save
68
- developer.reload
69
- expect(developer.user_id).to eq(other_user.id)
70
- end
71
-
72
- it "allow to rewrite boss id of developer" do
73
- developer.custom_boss_id = other_user.id
74
- developer.save
75
- developer.reload
76
- expect(developer.custom_boss_id).to eq(other_user.id)
77
- end
78
-
79
- end
80
-
81
- context "with calling validation" do
82
- before do
83
- Idea.send :validate_foreign_keys
84
- Project.send :validate_foreign_keys
85
- Issue.send :validate_foreign_keys
86
- Comment.send :validate_foreign_keys
87
- Member.send :validate_foreign_keys
88
- end
89
-
90
- let(:project) { Project.create user: user }
91
- let(:other_project) { Project.create user: other_user }
92
- let(:idea) { Idea.create user: user, project: project }
93
- let(:issue) { Issue.create user: user, project: project }
94
- let(:other_issue) { Issue.create user: other_user, project: other_project }
95
- let(:comment) { Comment.create user: user, issue: issue }
96
- let(:manager) { Manager.create user: user }
97
- let(:other_manager) { Manager.create user: User.create }
98
- let(:developer) { Developer.create user: user, boss: manager }
99
-
100
- it "uses same user ids by default" do
101
- expect(project.user_id).to eq(user.id)
102
- expect(idea.user_id).to eq(user.id)
103
- expect(issue.user_id).to eq(user.id)
104
- expect(comment.user_id).to eq(user.id)
105
- expect(manager.user_id).to eq(user.id)
106
- expect(developer.user_id).to eq(user.id)
107
- end
108
-
109
- it "does not allow to rewrite user id of idea" do
110
- idea.user_id = other_user.id
111
- idea.save
112
- expect(idea.errors.messages.values.flatten).to include("user_id of project does not match ideas user_id.")
113
- expect(idea.reload.user_id).to_not eq(other_user.id)
114
- end
115
-
116
- it "does not allow to rewrite user id of idea with random id" do
117
- idea.user_id = 42
118
- idea.save
119
- expect(idea.errors.messages.values.flatten).to include("user_id of project does not match ideas user_id.")
120
- expect(idea.reload.user_id).to_not eq(42)
121
- end
122
-
123
- it "does not allow to rewrite project id of idea" do
124
- idea.project_id = other_project.id
125
- idea.save
126
- expect(idea.errors.messages.values.flatten).to include("user_id of project does not match ideas user_id.")
127
- expect(idea.reload.user_id).to_not eq(other_project.id)
128
- end
129
-
130
- it "does not allow to rewrite user id of issue" do
131
- issue.user_id = other_user.id
132
- issue.save
133
- expect(issue.errors.messages.values.flatten).to include("user_id of project does not match issues user_id.")
134
- expect(issue.reload.user_id).to_not eq(other_user.id)
135
- end
136
-
137
- it "does not allow to rewrite project id of issue" do
138
- issue.project_id = other_project.id
139
- issue.save
140
- expect(issue.errors.messages.values.flatten).to include("user_id of project does not match issues user_id.")
141
- expect(issue.reload.user_id).to_not eq(other_project.id)
142
- end
143
-
144
- it "does not allow to rewrite user id of comment" do
145
- comment.user_id = other_user.id
146
- comment.save
147
- expect(comment.errors.messages.values.flatten).to include("user_id of issue does not match comments user_id.")
148
- expect(comment.reload.user_id).to_not eq(other_user.id)
149
- end
150
-
151
- it "does not allow to rewrite issue id of comment" do
152
- comment.issue_id = other_issue.id
153
- comment.save
154
- expect(comment.errors.messages.values.flatten).to include("user_id of issue does not match comments user_id.")
155
- expect(comment.reload.user_id).to_not eq(other_issue.id)
156
- end
157
-
158
- it "does allow to rewrite user id of project" do
159
- project.user_id = other_user.id
160
- project.save
161
- expect(project.errors).to be_empty
162
- expect(project.reload.user_id).to eq(other_user.id)
163
- end
164
-
165
- it "does not allow to rewrite user id of developer" do
166
- developer.user_id = other_user.id
167
- developer.save
168
- expect(developer.errors.messages.values.flatten).to include("user_id of boss does not match developers user_id.")
169
- expect(developer.reload.user_id).to_not eq(other_user.id)
170
- end
171
-
172
- it "does not allow to rewrite boss id of developer" do
173
- developer.custom_boss_id = other_manager.id
174
- developer.save
175
- expect(developer.errors.messages.values.flatten).to include("user_id of boss does not match developers user_id.")
176
- expect(developer.reload.custom_boss_id).to_not eq(other_manager.id)
177
- end
178
-
179
- end
180
-
181
- context "with calling private methods from model" do
182
- before { Issue.send :validate_foreign_keys }
183
-
184
- let(:issue) { Issue.create }
185
-
186
- it "does not allow to call private validate_foreign_key method" do
187
- expect{issue.validate_foreign_key("test", "unrat")}.to raise_exception(/private method `validate_foreign_key' called/)
188
- end
189
-
190
- it "does not allow to call private validate_foreign_keys_on_* methods" do
191
- expect{issue.validate_foreign_keys_on_user}.to raise_exception(/private method `validate_foreign_keys_on_user' called/)
192
- end
193
- end
194
-
195
- context "with calling validation with custom attributes hash" do
196
- before do
197
- Comment.class_eval do
198
- validate_foreign_keys on: :user, with: :issue # member is not in list - should be editable
199
- end
200
- end
201
-
202
- let(:project) { Project.create user: user }
203
- let(:other_project) { Project.create user: other_user }
204
- let(:issue) { Issue.create user: user, project: project }
205
- let(:other_issue) { Issue.create user: other_user, project: other_project }
206
- let(:comment) { Comment.create user: user, issue: issue }
207
- let(:manager) { Manager.create user: user }
208
- let(:other_manager) { Manager.create user: User.create }
209
-
210
- it "uses same user ids by default" do
211
- expect(project.user_id).to eq(user.id)
212
- expect(issue.user_id).to eq(user.id)
213
- expect(comment.user_id).to eq(user.id)
214
- expect(manager.user_id).to eq(user.id)
215
- end
216
-
217
- it "does not allow to rewrite issue id of comment" do
218
- comment.issue_id = other_issue.id
219
- comment.save
220
- expect(comment.errors.messages.values.flatten).to include("user_id of issue does not match comments user_id.")
221
- expect(comment.reload.issue_id).to_not eq(other_issue.id)
222
- end
223
-
224
- # NOTE: this is possible here because Issue model is not configured to check ids
225
- # comment model can only check id against issue model if it is present
226
- it "does allow to rewrite issue id of comment with random id" do
227
- comment.issue_id = 42
228
- comment.save
229
- comment.reload
230
- expect(comment.issue_id).to eq(42)
231
- end
232
-
233
- it "allow to rewrite member id of comment" do
234
- comment.member_id = other_manager.id
235
- comment.save
236
- comment.reload
237
- expect(comment.member_id).to eq(other_manager.id)
238
- end
239
-
240
- it "allow to rewrite user id of issue" do
241
- issue.user_id = other_user.id
242
- issue.save
243
- issue.reload
244
- expect(issue.user_id).to eq(other_user.id)
245
- end
246
-
247
- it "allow to rewrite user id of manager" do
248
- manager.user_id = other_user.id
249
- manager.save
250
- manager.reload
251
- expect(manager.user_id).to eq(other_user.id)
252
- end
253
-
254
- end
255
-
256
- context "with calling validation and wrong attributes hash" do
257
-
258
- it "raises error due to wrong :on key" do
259
- expect{Idea.class_eval { validate_foreign_keys on: :not_existing }}.to raise_error("No foreign key for relation not_existing on ideas table!")
260
- end
261
-
262
- it "raises error due to not related :on key" do
263
- expect{Project.class_eval { validate_foreign_keys on: :comment }}.to raise_error("No foreign key for relation comment on projects table!")
264
- end
265
-
266
- it "raises error due to wrong :with key" do
267
- expect{Idea.class_eval { validate_foreign_keys with: :not_existing }}.to raise_error('Unknown relation in ["not_existing"]!')
268
- end
269
-
270
- end
271
-
272
- context "with calling validation and missing relations" do
273
-
274
- it "raises error due to no existing relations" do
275
- expect{Dummy.class_eval { validate_foreign_keys }}.to raise_error("Can't find any belongs_to relations for Dummy class. Put validation call below association definitions!")
276
- end
277
-
278
- end
279
-
280
-
281
- context "with calling validation and missing foreign key on self" do
282
-
283
- before do
284
- Issue.class_eval do
285
- validate_foreign_keys
286
- end
287
- end
288
-
289
- let(:project) { Project.create user: user }
290
- let(:issue) { Issue.create project: project }
291
-
292
- it "does not allow to rewrite user id of issue" do
293
- issue.user_id = other_user.id
294
- issue.save
295
- expect(issue.errors.messages.values.flatten).to include("user_id of project does not match issues user_id.")
296
- expect(issue.reload.user_id).to_not eq(other_user.id)
297
- end
298
-
299
- it "does not allow to rewrite user id of issue with random id" do
300
- issue.user_id = 42
301
- issue.save
302
- expect(issue.errors.messages.values.flatten).to include("user_id of project does not match issues user_id.")
303
- expect(issue.reload.user_id).to_not eq(42)
304
- end
305
-
306
-
307
- end
308
-
309
- context "with calling validation and missing foreign key on relation" do
310
-
311
- before do
312
- Issue.class_eval do
313
- validate_foreign_keys
314
- end
315
- end
316
-
317
- let(:project) { Project.create }
318
- let(:other_project) { Project.create }
319
- let(:issue) { Issue.create project: project, user: user }
320
-
321
- it "allow to rewrite user id of issue" do
322
- issue.user_id = other_user.id
323
- issue.save
324
- issue.reload
325
- expect(issue.user_id).to eq(other_user.id)
326
- end
327
-
328
- it "allow to rewrite project id of issue" do
329
- issue.project_id = other_project.id
330
- issue.save
331
- issue.reload
332
- expect(issue.project_id).to eq(other_project.id)
333
- end
334
-
335
- end
336
-
337
- end