diff --git a/CHANGELOG b/CHANGELOG index cbaba99..82abe5f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,9 @@ +0.6.0 +===== +* setting an association will now result in model.changed? to be true. + Also model.changes will include the old attribute key with the old value. + This allows the :autosave option on associated objects to work correctly. + 0.5.8 ===== * fix preloading of HABTM associations in ActiveRecord >= 4.0 diff --git a/bin/run_all_specs b/bin/run_all_specs new file mode 100755 index 0000000..70551d0 --- /dev/null +++ b/bin/run_all_specs @@ -0,0 +1,25 @@ +#!/bin/sh + +DIR=`pwd` + +if [[ $DIR == *bin ]]; then + cd .. +fi + +echo "Your ruby version: " +echo `ruby -v` + +ls -c gemfiles/*.gemfile | while read line +do + + echo "Run Spec for gemfile: $line" + export BUNDLE_GEMFILE=$line + bundle install + bundle exec rspec + echo "" + echo "" + echo "" + echo "=========" +done + +unset BUNDLE_GEMFILE diff --git a/deferred_associations.gemspec b/deferred_associations.gemspec index fbd5037..0efc622 100644 --- a/deferred_associations.gemspec +++ b/deferred_associations.gemspec @@ -2,11 +2,11 @@ Gem::Specification.new do |s| s.name = 'deferred_associations' - s.version = '0.5.8' + s.version = '0.6.0' s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to? :required_rubygems_version= s.authors = ['Martin Koerner', 'Tyler Rick', 'Alessio Caiazza'] - s.date = '2016-03-08' + s.date = '2016-05-06' s.description = "Makes ActiveRecord defer/postpone saving the records you add to an habtm (has_and_belongs_to_many) or has_many\n association until you call model.save, allowing validation in the style of normal attributes. Additionally you\n can check inside before_save filters, if the association was altered." s.email = 'martin.koerner@objectfab.de' s.licenses = 'MIT' @@ -20,6 +20,7 @@ Gem::Specification.new do |s| 'VERSION', 'deferred_associations.gemspec', 'init.rb', + 'bin/run_all_specs', 'lib/array_to_association_wrapper.rb', 'lib/deferred_associations.rb', 'lib/has_and_belongs_to_many_with_deferred_save.rb', diff --git a/lib/has_and_belongs_to_many_with_deferred_save.rb b/lib/has_and_belongs_to_many_with_deferred_save.rb index 4e6915b..fe4ec63 100644 --- a/lib/has_and_belongs_to_many_with_deferred_save.rb +++ b/lib/has_and_belongs_to_many_with_deferred_save.rb @@ -30,6 +30,7 @@ def has_and_belongs_to_many_with_deferred_save(*args) define_method "#{collection_name}_with_deferred_save=" do |collection| # puts "has_and_belongs_to_many_with_deferred_save: #{collection_name} = #{collection.collect(&:id).join(',')}" send "unsaved_#{collection_name}=", collection + attribute_will_change!(collection_singular_ids) end define_method "#{collection_name}_with_deferred_save" do |*method_args| diff --git a/lib/has_many_with_deferred_save.rb b/lib/has_many_with_deferred_save.rb index 9f6946e..66e7636 100644 --- a/lib/has_many_with_deferred_save.rb +++ b/lib/has_many_with_deferred_save.rb @@ -3,6 +3,7 @@ module Associations module ClassMethods def has_many_with_deferred_save(*args) collection_name = args[0].to_s + collection_singular_ids = "#{collection_name.singularize}_ids" return if method_defined?("#{collection_name}_with_deferred_save") @@ -14,18 +15,19 @@ def has_many_with_deferred_save(*args) after_save "hmwds_update_#{collection_name}" - define_obj_setter collection_name + define_obj_setter collection_name, collection_singular_ids define_obj_getter collection_name - define_id_setter collection_name - define_id_getter collection_name + define_id_setter collection_name, collection_singular_ids + define_id_getter collection_name, collection_singular_ids define_update_method collection_name define_reload_method collection_name end - def define_obj_setter(collection_name) + def define_obj_setter(collection_name, collection_singular_ids) define_method("#{collection_name}_with_deferred_save=") do |objs| instance_variable_set "@hmwds_temp_#{collection_name}", objs || [] + attribute_will_change!(collection_singular_ids) end method_name = "#{collection_name}=" @@ -56,10 +58,9 @@ def define_obj_getter(collection_name) alias_method_chain collection_name, :deferred_save end - def define_id_setter(collection_name) + def define_id_setter(collection_name, collection_singular_ids) # only needed for ActiveRecord >= 3.0 if ActiveRecord::VERSION::STRING >= '3' - collection_singular_ids = "#{collection_name.singularize}_ids" define_method "#{collection_singular_ids}_with_deferred_save=" do |ids| ids = Array.wrap(ids).reject(&:blank?) new_values = send("#{collection_name}_without_deferred_save").klass.find(ids) @@ -69,8 +70,7 @@ def define_id_setter(collection_name) end end - def define_id_getter(collection_name) - collection_singular_ids = "#{collection_name.singularize}_ids" + def define_id_getter(collection_name, collection_singular_ids) define_method "#{collection_singular_ids}_with_deferred_save" do send(collection_name).map { |e| e[:id] } end diff --git a/spec/db/schema.rb b/spec/db/schema.rb index 466b486..fef1bda 100644 --- a/spec/db/schema.rb +++ b/spec/db/schema.rb @@ -35,4 +35,9 @@ t.column 'name', :string t.column 'table_id', :integer end + + create_table 'windows', force: true do |t| + t.column 'name', :string + t.column 'room_id', :integer + end end diff --git a/spec/has_and_belongs_to_many_with_deferred_save_spec.rb b/spec/has_and_belongs_to_many_with_deferred_save_spec.rb index 1b4970f..175f37e 100644 --- a/spec/has_and_belongs_to_many_with_deferred_save_spec.rb +++ b/spec/has_and_belongs_to_many_with_deferred_save_spec.rb @@ -238,4 +238,23 @@ expect(@door.rooms.include?(@rooms[1])).to be false end end + + describe 'tables' do + before :all do + @table1 = Table.create(name: 'Table1', room_id: Room.create(name: 'Kitchen').id) + @table2 = Table.create(name: 'Table2', room_id: Room.create(name: 'Dining room').id) + @doors = [Door.create(name: 'Door1'), Door.create(name: 'Door2')] + end + + it 'saves doors of associated room, if table gets saved' do + @table1.room_with_autosave.doors = @doors + @table2.room_with_autosave.door_ids = [@doors.first.id] + expect(@table1.room_with_autosave).to be_changed + expect(@table2.room_with_autosave).to be_changed + @table1.save! + @table2.save! + expect(@table1.room.doors).to eq @doors + expect(@table2.room.doors).to eq [@doors.first] + end + end end diff --git a/spec/has_many_with_deferred_save_spec.rb b/spec/has_many_with_deferred_save_spec.rb index ea987df..35816b7 100644 --- a/spec/has_many_with_deferred_save_spec.rb +++ b/spec/has_many_with_deferred_save_spec.rb @@ -100,4 +100,23 @@ expect { Marshal.dump(Room.new.chairs) }.not_to raise_exception end end + + describe 'with autosave option' do + before :all do + @table3 = Table.create(name: 'Table3', room_id: Room.create(name: 'Kitchen').id) + @table4 = Table.create(name: 'Table4', room_id: Room.create(name: 'Dining room').id) + @windows = [Window.create(name: 'South'), Window.create(name: 'West'), Window.create(name: 'East')] + end + + it 'saves windows of associated room, if table gets saved' do + @table3.room_with_autosave.windows = [@windows.first, @windows.second] + @table4.room_with_autosave.window_ids = [@windows.third.id] + expect(@table3.room_with_autosave).to be_changed + expect(@table4.room_with_autosave).to be_changed + @table3.save! + @table4.save! + expect(@table3.room.windows).to eq [@windows.first, @windows.second] + expect(@table4.room.windows).to eq [@windows.third] + end + end end diff --git a/spec/models/room.rb b/spec/models/room.rb index 4b3756f..1aad20b 100644 --- a/spec/models/room.rb +++ b/spec/models/room.rb @@ -10,18 +10,17 @@ class Room < ActiveRecord::Base has_and_belongs_to_many :people2, class_name: 'Person' has_and_belongs_to_many_with_deferred_save :doors + has_many_with_deferred_save :windows has_many_with_deferred_save :tables has_many_with_deferred_save :chairs, through: :tables # TODO: test compatibility with through associations - has_and_belongs_to_many_with_deferred_save :doors - has_many_with_deferred_save :tables before_save :diff_after_module validate :people_count def people_count - errors.add :people, 'This room has reached its maximum occupancy' if people.size > maximum_occupancy + errors.add :people, 'This room has reached its maximum occupancy' if maximum_occupancy && people.size > maximum_occupancy end # Just in case they try to bypass our new accessor and call people_without_deferred_save directly... diff --git a/spec/models/table.rb b/spec/models/table.rb index 56b8e01..b071ff5 100644 --- a/spec/models/table.rb +++ b/spec/models/table.rb @@ -1,6 +1,7 @@ class Table < ActiveRecord::Base belongs_to :room + belongs_to :room_with_autosave, class_name: 'Room', autosave: true, foreign_key: 'room_id' has_many_with_deferred_save :chairs end diff --git a/spec/models/window.rb b/spec/models/window.rb new file mode 100644 index 0000000..1af90d3 --- /dev/null +++ b/spec/models/window.rb @@ -0,0 +1,4 @@ +class Window < ActiveRecord::Base + + belongs_to :room +end