association_accessors 1.3.0
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 +7 -0
- data/.rspec +3 -0
- data/Appraisals +25 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +254 -0
- data/Rakefile +27 -0
- data/association_accessors.gemspec +39 -0
- data/bin/test +21 -0
- data/gemfiles/activerecord_4.1.gemfile +7 -0
- data/gemfiles/activerecord_4.1.gemfile.lock +67 -0
- data/gemfiles/activerecord_4.2.gemfile +7 -0
- data/gemfiles/activerecord_4.2.gemfile.lock +67 -0
- data/gemfiles/activerecord_5.0.gemfile +7 -0
- data/gemfiles/activerecord_5.0.gemfile.lock +63 -0
- data/gemfiles/activerecord_5.1.gemfile +7 -0
- data/gemfiles/activerecord_5.1.gemfile.lock +63 -0
- data/gemfiles/activerecord_5.2.gemfile +7 -0
- data/gemfiles/activerecord_5.2.gemfile.lock +63 -0
- data/gemfiles/rspec_2.gemfile +7 -0
- data/gemfiles/rspec_2.gemfile.lock +58 -0
- data/lib/association_accessors.rb +30 -0
- data/lib/association_accessors/collection_association.rb +35 -0
- data/lib/association_accessors/singular_association.rb +19 -0
- data/lib/association_accessors/test/matcher.rb +60 -0
- data/lib/association_accessors/version.rb +3 -0
- data/spec/association_accessors_spec.rb +5 -0
- data/spec/dummy.rb +99 -0
- data/spec/matcher_spec.rb +56 -0
- data/spec/spec_helper.rb +23 -0
- data/spec/with_association/belongs_to_spec.rb +33 -0
- data/spec/with_association/has_and_belongs_to_many_spec.rb +45 -0
- data/spec/with_association/has_many_spec.rb +45 -0
- data/spec/with_association/has_many_through_spec.rb +27 -0
- data/spec/with_association/has_one_spec.rb +33 -0
- data/spec/with_association/has_one_through_spec.rb +43 -0
- data/spec/with_association/polymorphic/belongs_to_spec.rb +38 -0
- data/spec/with_association/polymorphic/has_many_spec.rb +44 -0
- data/spec/with_association/polymorphic/has_one_spec.rb +33 -0
- data/spec/with_association/with_custom_name_spec.rb +33 -0
- data/spec/with_attribute_spec.rb +47 -0
- metadata +203 -0
@@ -0,0 +1,60 @@
|
|
1
|
+
module AssociationAccessors
|
2
|
+
module Test
|
3
|
+
def have_association_accessor_for association
|
4
|
+
Matcher.new association
|
5
|
+
end
|
6
|
+
|
7
|
+
class Matcher
|
8
|
+
attr_reader :failure_message, :subject, :association_name, :attribute, :association
|
9
|
+
|
10
|
+
def initialize association_name
|
11
|
+
@association_name = association_name
|
12
|
+
end
|
13
|
+
|
14
|
+
def description
|
15
|
+
"have association accessor for #{association_name.inspect} with attribute #{attribute.inspect}."
|
16
|
+
end
|
17
|
+
|
18
|
+
def matches? subject
|
19
|
+
@subject = subject
|
20
|
+
@association = get_association
|
21
|
+
|
22
|
+
check_attribute!
|
23
|
+
|
24
|
+
has_accessors?
|
25
|
+
end
|
26
|
+
|
27
|
+
def with_attribute attribute
|
28
|
+
@attribute = attribute
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def get_association
|
36
|
+
subject.association(association_name)
|
37
|
+
end
|
38
|
+
|
39
|
+
def check_attribute!
|
40
|
+
raise ArgumentError, "'with_attribute' is required" if attribute.nil?
|
41
|
+
end
|
42
|
+
|
43
|
+
def has_accessors?
|
44
|
+
accessor_name =
|
45
|
+
if association.reflection.collection?
|
46
|
+
:"#{association_name.to_s.singularize}_#{attribute.to_s.pluralize}"
|
47
|
+
else
|
48
|
+
:"#{association_name}_#{attribute}"
|
49
|
+
end
|
50
|
+
|
51
|
+
if subject.respond_to?(accessor_name) && subject.respond_to?(:"#{accessor_name}=")
|
52
|
+
true
|
53
|
+
else
|
54
|
+
@failure_message = "reader and/or writer `#{accessor_name}` not defined on #{subject.class.name}."
|
55
|
+
false
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/spec/dummy.rb
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
3
|
+
ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
|
4
|
+
|
5
|
+
ActiveRecord::Schema.define do
|
6
|
+
create_table :authors, force: true do |t|
|
7
|
+
t.string :serial
|
8
|
+
end
|
9
|
+
|
10
|
+
create_table :books, force: true do |t|
|
11
|
+
t.string :serial
|
12
|
+
t.integer :author_id
|
13
|
+
end
|
14
|
+
|
15
|
+
create_table :addresses, force: true do |t|
|
16
|
+
t.string :serial
|
17
|
+
t.integer :author_id
|
18
|
+
end
|
19
|
+
|
20
|
+
create_table :chapters, force: true do |t|
|
21
|
+
t.string :serial
|
22
|
+
t.integer :book_id
|
23
|
+
end
|
24
|
+
|
25
|
+
create_table :publishers, force: true do |t|
|
26
|
+
t.string :uuid
|
27
|
+
end
|
28
|
+
|
29
|
+
create_join_table :authors, :publishers
|
30
|
+
|
31
|
+
create_table :images, force: true do |t|
|
32
|
+
t.string :serial
|
33
|
+
t.string :imageable_type
|
34
|
+
t.integer :imageable_id
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class Serialable < ActiveRecord::Base
|
39
|
+
include AssociationAccessors
|
40
|
+
self.abstract_class = true
|
41
|
+
before_create do
|
42
|
+
send :serial=, SecureRandom.urlsafe_base64
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class Author < Serialable
|
47
|
+
has_many :books
|
48
|
+
association_accessor_for :books, with_attribute: :serial
|
49
|
+
|
50
|
+
has_one :address
|
51
|
+
association_accessor_for :address, with_attribute: :serial
|
52
|
+
|
53
|
+
has_many :chapters, through: :books
|
54
|
+
association_accessor_for :chapters, with_attribute: :serial
|
55
|
+
|
56
|
+
has_and_belongs_to_many :publishers
|
57
|
+
association_accessor_for :publishers, with_attribute: :uuid
|
58
|
+
|
59
|
+
has_one :image, as: :imageable
|
60
|
+
association_accessor_for :image, with_attribute: :serial
|
61
|
+
end
|
62
|
+
|
63
|
+
class Book < Serialable
|
64
|
+
OPTIONAL = ActiveRecord.gem_version.segments.first == 5 ? { optional: true } : {}
|
65
|
+
|
66
|
+
belongs_to :author, OPTIONAL
|
67
|
+
association_accessor_for :author, with_attribute: :serial
|
68
|
+
|
69
|
+
belongs_to :writer, { class_name: 'Author', foreign_key: :author_id }.merge(OPTIONAL)
|
70
|
+
association_accessor_for :writer, with_attribute: :serial
|
71
|
+
|
72
|
+
has_one :address, through: :author
|
73
|
+
association_accessor_for :address, with_attribute: :serial
|
74
|
+
|
75
|
+
has_many :images, as: :imageable
|
76
|
+
association_accessor_for :images, with_attribute: :serial
|
77
|
+
|
78
|
+
has_many :chapters
|
79
|
+
end
|
80
|
+
|
81
|
+
class Address < Serialable
|
82
|
+
belongs_to :author
|
83
|
+
end
|
84
|
+
|
85
|
+
class Chapter < Serialable
|
86
|
+
belongs_to :book
|
87
|
+
end
|
88
|
+
|
89
|
+
class Publisher < ActiveRecord::Base
|
90
|
+
has_and_belongs_to_many :authors
|
91
|
+
before_create do
|
92
|
+
send :uuid=, SecureRandom.uuid
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
class Image < Serialable
|
97
|
+
belongs_to :imageable, polymorphic: true
|
98
|
+
association_accessor_for :imageable, with_attribute: :serial
|
99
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
RSpec.configure do |config|
|
2
|
+
config.include AssociationAccessors::Test
|
3
|
+
|
4
|
+
# only the matcher should be tested against older version of RSpec
|
5
|
+
config.filter_run matcher: true if RSPEC_MAJOR_VERSION == 2
|
6
|
+
end
|
7
|
+
|
8
|
+
RSpec.describe 'the test matcher', matcher: true do
|
9
|
+
subject { Author.new }
|
10
|
+
|
11
|
+
it 'raises ActiveRecord::AssociationNotFoundError if the association does not exist on subject.' do
|
12
|
+
expect {
|
13
|
+
should have_association_accessor_for(:book).with_attribute(:serial)
|
14
|
+
}.to raise_exception ActiveRecord::AssociationNotFoundError, /Association named 'book' was not found on Author/
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'raises ArgumentError if `with_attribute` is blank.' do
|
18
|
+
expect {
|
19
|
+
should have_association_accessor_for(:books)
|
20
|
+
}.to raise_exception ArgumentError, /'with_attribute' is required/
|
21
|
+
end
|
22
|
+
|
23
|
+
describe 'for singular association' do
|
24
|
+
it 'fails if subject does not respond to the reader or writer `[association]_[attribute]`.' do
|
25
|
+
expect {
|
26
|
+
should have_association_accessor_for(:address).with_attribute(:uuid)
|
27
|
+
}.to raise_exception RSpec::Expectations::ExpectationNotMetError, /reader and\/or writer `address_uuid` not defined on Author/
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'passes if subject responds to the reader and writer `[association]_[attribute]`.' do
|
31
|
+
should have_association_accessor_for(:address).with_attribute(:serial)
|
32
|
+
should have_association_accessor_for(:image).with_attribute(:serial)
|
33
|
+
expect(Book.new).to have_association_accessor_for(:author).with_attribute(:serial)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe 'for collection association' do
|
38
|
+
it 'fails if subject does not respond to the reader or writer `[association_singular]_[attribute_plural]`.' do
|
39
|
+
expect {
|
40
|
+
should have_association_accessor_for(:chapters).with_attribute(:uuid)
|
41
|
+
}.to raise_exception RSpec::Expectations::ExpectationNotMetError, /reader and\/or writer `chapter_uuids` not defined on Author/
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'passes if subject responds to the reader and writer `[association_singular]_[attribute_plural]`.' do
|
45
|
+
should have_association_accessor_for(:books).with_attribute(:serial)
|
46
|
+
should have_association_accessor_for(:chapters).with_attribute(:serial)
|
47
|
+
should have_association_accessor_for(:publishers).with_attribute(:uuid)
|
48
|
+
expect(Book.new).to have_association_accessor_for(:images).with_attribute(:serial)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'has a concise but expressive default output.' do
|
53
|
+
expect(have_association_accessor_for(:books).with_attribute(:serial).description)
|
54
|
+
.to eq 'have association accessor for :books with attribute :serial.'
|
55
|
+
end
|
56
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require "bundler/setup"
|
2
|
+
require "association_accessors"
|
3
|
+
require 'dummy'
|
4
|
+
|
5
|
+
RSPEC_MAJOR_VERSION = RSpec::Core::Version::STRING.split('.').first.to_i
|
6
|
+
|
7
|
+
RSpec.configure do |config|
|
8
|
+
if RSPEC_MAJOR_VERSION == 3
|
9
|
+
# Enable flags like --only-failures and --next-failure
|
10
|
+
config.example_status_persistence_file_path = ".rspec_status"
|
11
|
+
|
12
|
+
# Disable RSpec exposing methods globally on `Module` and `main`
|
13
|
+
config.disable_monkey_patching!
|
14
|
+
end
|
15
|
+
|
16
|
+
config.expect_with :rspec do |c|
|
17
|
+
c.syntax = :expect
|
18
|
+
end
|
19
|
+
|
20
|
+
config.filter_run_excluding activerecord: proc { |versions|
|
21
|
+
versions.none? { |version| ActiveRecord.gem_version.to_s.include? version }
|
22
|
+
}
|
23
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
RSpec.describe 'for `belongs_to` association' do
|
2
|
+
let!(:author) { Author.create! }
|
3
|
+
let!(:book) { Book.create! author: author }
|
4
|
+
|
5
|
+
it 'generates `#[association_name]_[attribute_name]` accessor.' do
|
6
|
+
expect(book).to respond_to :author_serial, :author_serial=
|
7
|
+
end
|
8
|
+
|
9
|
+
describe '`#[association_name]_[attribute_name]`' do
|
10
|
+
it 'returns the value of the `[attribute]` of the associated record if there is any.' do
|
11
|
+
expect { book.author = nil }.to change(book, :author_serial).from(author.serial).to nil
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '`#[association_name]_[attribute_name]=(value)`' do
|
16
|
+
it 'sets the association value to nil if `value` is nil.' do
|
17
|
+
expect { book.author_serial = nil }.to change(book, :author).from(author).to nil
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'sets the association value to the record queried by its `[attribute]` having the value `value` if such record exists.' do
|
21
|
+
new_author = Author.create!
|
22
|
+
expect { book.author_serial = new_author.serial }.to change(book, :author).from(author).to new_author
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'raises ActiveRecord::RecordNotFound if record with `[attribute]` = `value` does not exist.', activerecord: [ '4.1' ] do
|
26
|
+
expect { book.author_serial = author.serial.next }.to raise_exception ActiveRecord::RecordNotFound
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'raises ActiveRecord::RecordNotFound if record with `[attribute]` = `value` does not exist.', activerecord: [ '4.2', '5' ] do
|
30
|
+
expect { book.author_serial = author.serial.next }.to raise_exception ActiveRecord::RecordNotFound, "Couldn't find Author"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
RSpec.describe 'for `has_and_belongs_to_many` association' do
|
2
|
+
let!(:author_1) { Author.create! }
|
3
|
+
let!(:author_2) { Author.create! }
|
4
|
+
let!(:publisher_1) { Publisher.create! authors: [ author_1 ] }
|
5
|
+
let!(:publisher_2) { Publisher.create! authors: [ author_2 ] }
|
6
|
+
|
7
|
+
it 'generates `#[association_name.singularize]_[attribute_name.pluralize]` accessor.' do
|
8
|
+
expect(author_1).to respond_to :publisher_uuids, :publisher_uuids=
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '`#[association_name.singularize]_[attribute_name.pluralize]`' do
|
12
|
+
it 'returns an array with the values of `[attribute]` of the associated records.' do
|
13
|
+
expect(author_1.publisher_uuids).to eq [ publisher_1.uuid ]
|
14
|
+
expect(author_2.publisher_uuids).to eq [ publisher_2.uuid ]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '`#[association_name.singularize]_[attribute_name.pluralize]`=(values)' do
|
19
|
+
it 'sets the association value to the records queried by `[attribute]` = `value` if all exist.' do
|
20
|
+
expect { author_1.publisher_uuids = [] }.to change { author_1.publishers.ids }.from([ publisher_1.id ]).to []
|
21
|
+
expect { author_2.publisher_uuids = [ publisher_1.uuid ] }.to change { author_2.publishers.ids }.from([ publisher_2.id ]).to [ publisher_1.id ]
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'raises ActiveRecord::RecordNotFound if any of the given `values` has no record.', activerecord: [ '4' ] do
|
25
|
+
expect { author_2.publisher_uuids = [ publisher_1.uuid, publisher_2.uuid.next ] }
|
26
|
+
.to raise_exception(ActiveRecord::RecordNotFound,
|
27
|
+
%{Couldn't find all Publishers with 'id': ("#{publisher_1.uuid}", "#{publisher_2.uuid.next}")} +
|
28
|
+
%{ (found 1 results, but was looking for 2)})
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'raises ActiveRecord::RecordNotFound if any of the given `values` has no record.', activerecord: [ '5.0', '5.1' ] do
|
32
|
+
expect { author_2.publisher_uuids = [ publisher_1.uuid, publisher_2.uuid.next ] }
|
33
|
+
.to raise_exception(ActiveRecord::RecordNotFound,
|
34
|
+
%{Couldn't find all Publishers with 'uuid': ("#{publisher_1.uuid}", "#{publisher_2.uuid.next}")} +
|
35
|
+
%{ (found 1 results, but was looking for 2)})
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'raises ActiveRecord::RecordNotFound if any of the given `values` has no record.', activerecord: [ '5.2' ] do
|
39
|
+
expect { author_2.publisher_uuids = [ publisher_1.uuid, publisher_2.uuid.next ] }
|
40
|
+
.to raise_exception(ActiveRecord::RecordNotFound,
|
41
|
+
%{Couldn't find all Publishers with 'uuid': ("#{publisher_1.uuid}", "#{publisher_2.uuid.next}")} +
|
42
|
+
%{ (found 1 results, but was looking for 2). Couldn't find Publisher with uuid "#{publisher_2.uuid.next}".})
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
RSpec.describe 'for `has_many` association' do
|
2
|
+
let!(:author_1) { Author.create! }
|
3
|
+
let!(:author_2) { Author.create! }
|
4
|
+
let!(:book_1) { Book.create! author: author_1 }
|
5
|
+
let!(:book_2) { Book.create! author: author_1 }
|
6
|
+
|
7
|
+
it 'generates `#[association_name.singularize]_[attribute_name.pluralize]` accessor.' do
|
8
|
+
expect(author_1).to respond_to :book_serials, :book_serials=
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '`#[association_name.singularize]_[attribute_name.pluralize]`' do
|
12
|
+
it 'returns an array with the values of `[attribute]` of the associated records.' do
|
13
|
+
expect(author_1.book_serials).to match_array [ book_1.serial, book_2.serial ]
|
14
|
+
expect(author_2.book_serials).to eq []
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '`#[association_name.singularize]_[attribute_name.pluralize]`=(values)' do
|
19
|
+
it 'sets the association value to the records queried by `[attribute]` = `value` if all exist.' do
|
20
|
+
expect { author_1.book_serials = [] }.to change { author_1.books.ids }.from([ book_1.id, book_2.id ]).to []
|
21
|
+
expect { author_2.book_serials = [ book_1.serial ] }.to change { author_2.books.ids }.from([]).to [ book_1.id ]
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'raises ActiveRecord::RecordNotFound if any of the given `values` has no record.', activerecord: [ '4' ] do
|
25
|
+
expect { author_2.book_serials = [ book_1.serial, book_2.serial.next ] }
|
26
|
+
.to raise_exception(ActiveRecord::RecordNotFound,
|
27
|
+
%{Couldn't find all Books with 'id': ("#{book_1.serial}", "#{book_2.serial.next}")} +
|
28
|
+
%{ (found 1 results, but was looking for 2)})
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'raises ActiveRecord::RecordNotFound if any of the given `values` has no record.', activerecord: [ '5.0', '5.1' ] do
|
32
|
+
expect { author_2.book_serials = [ book_1.serial, book_2.serial.next ] }
|
33
|
+
.to raise_exception(ActiveRecord::RecordNotFound,
|
34
|
+
%{Couldn't find all Books with 'serial': ("#{book_1.serial}", "#{book_2.serial.next}")} +
|
35
|
+
%{ (found 1 results, but was looking for 2)})
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'raises ActiveRecord::RecordNotFound if any of the given `values` has no record.', activerecord: [ '5.2' ] do
|
39
|
+
expect { author_2.book_serials = [ book_1.serial, book_2.serial.next ] }
|
40
|
+
.to raise_exception(ActiveRecord::RecordNotFound,
|
41
|
+
%{Couldn't find all Books with 'serial': ("#{book_1.serial}", "#{book_2.serial.next}")} +
|
42
|
+
%{ (found 1 results, but was looking for 2). Couldn't find Book with serial "#{book_2.serial.next}".})
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
RSpec.describe 'for `has_many through:` association' do
|
2
|
+
let!(:author_1) { Author.create! }
|
3
|
+
let!(:author_2) { Author.create! }
|
4
|
+
let!(:book_1) { Book.create! author: author_1 }
|
5
|
+
let!(:book_2) { Book.create! author: author_2 }
|
6
|
+
let!(:chapter_1) { Chapter.create! book: book_1 }
|
7
|
+
let!(:chapter_2) { Chapter.create! book: book_2 }
|
8
|
+
|
9
|
+
it 'generates `#[association_name.singularize]_[attribute_name.pluralize]` accessor.' do
|
10
|
+
expect(author_1).to respond_to :chapter_serials, :chapter_serials=
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '`#[association_name.singularize]_[attribute_name.pluralize]`' do
|
14
|
+
it 'returns an array with the values of `[attribute]` of the associated records.' do
|
15
|
+
expect(author_1.chapter_serials).to eq [ chapter_1.serial ]
|
16
|
+
expect(author_2.chapter_serials).to eq [ chapter_2.serial ]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '`#[association_name.singularize]_[attribute_name.pluralize]`=(values)' do
|
21
|
+
it 'raises ActiveRecord::HasManyThroughCantAssociateThroughHasOneOrManyReflection.' do
|
22
|
+
expect { author_1.chapter_serials = [] }
|
23
|
+
.to raise_exception(ActiveRecord::HasManyThroughCantAssociateThroughHasOneOrManyReflection,
|
24
|
+
%{Cannot modify association 'Author#chapters' because the source reflection class 'Chapter' is associated to 'Book' via :has_many.})
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
RSpec.describe 'for `has_one` association' do
|
2
|
+
let!(:author) { Author.create! }
|
3
|
+
let!(:address) { Address.create! author: author }
|
4
|
+
|
5
|
+
it 'generates `#[association_name]_[attribute_name]` accessor.' do
|
6
|
+
expect(author).to respond_to :address_serial, :address_serial=
|
7
|
+
end
|
8
|
+
|
9
|
+
describe '`#[association_name]_[attribute_name]`' do
|
10
|
+
it 'returns the value of the `[attribute]` of the associated record if there is any.' do
|
11
|
+
expect { author.address = nil }.to change(author, :address_serial).from(address.serial).to nil
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '`#[association_name]_[attribute_name]=(value)`' do
|
16
|
+
it 'sets the association value to nil if `value` is nil.' do
|
17
|
+
expect { author.address_serial = nil }.to change(author, :address).from(address).to nil
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'sets the association value to the record queried by its `[attribute]` having the value `value` if such record exists.' do
|
21
|
+
new_address = Address.create!
|
22
|
+
expect { author.address_serial = new_address.serial }.to change(author, :address).from(address).to new_address
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'raises ActiveRecord::RecordNotFound if record with `[attribute]` = `value` does not exist.', activerecord: [ '4.1' ] do
|
26
|
+
expect { author.address_serial = address.serial.next }.to raise_exception ActiveRecord::RecordNotFound
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'raises ActiveRecord::RecordNotFound if record with `[attribute]` = `value` does not exist.', activerecord: [ '4.2', '5' ] do
|
30
|
+
expect { author.address_serial = address.serial.next }.to raise_exception ActiveRecord::RecordNotFound, "Couldn't find Address"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|