From 3cd1ac5d30e2891ecd687ed1d3107f3b649bd9f1 Mon Sep 17 00:00:00 2001 From: Josh Susser Date: Tue, 19 Aug 2008 17:43:40 -0700 Subject: [PATCH] basic parameterized has_many association with create and update --- activerecord/lib/active_record/associations.rb | 31 +++++++++++++++++++++++- activerecord/test/cases/associations_test.rb | 9 +++++++ activerecord/test/models/basket.rb | 3 ++ activerecord/test/schema/schema.rb | 9 +++++++ 4 files changed, 51 insertions(+), 1 deletions(-) create mode 100644 activerecord/test/models/basket.rb diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index aca2d77..c158fd2 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -766,6 +766,9 @@ module ActiveRecord collection_accessor_methods(reflection, HasManyThroughAssociation) else collection_accessor_methods(reflection, HasManyAssociation) + if options[:parameterize] + parameterize_methods(reflection) + end end end @@ -1318,6 +1321,32 @@ module ActiveRecord end end + def parameterize_methods(reflection) + class_eval(<<-EVAL_END, __FILE__, __LINE__) + attr_writer :create_#{reflection.name}_params + attr_writer :update_#{reflection.name}_params + + before_validation :process_#{reflection.name}_params + + def process_#{reflection.name}_params + no_errors = true + unless @create_#{reflection.name}_params.blank? + @create_#{reflection.name}_params.each_pair do |key, params| + self.#{reflection.name}.build(params) unless params.all? { |k,v| v.blank? } + end + end + if @update_#{reflection.name}_params + @update_#{reflection.name}_params.each_pair do |key, params| + rec = self.#{reflection.name}.find(key.to_s.to_i) + rec.attributes = params + no_errors &&= rec.save if rec.changed? + end + end + no_errors + end + EVAL_END + end + def add_single_associated_validation_callbacks(association_name) method_name = "validate_associated_records_for_#{association_name}".to_sym define_method(method_name) do @@ -1508,7 +1537,7 @@ module ActiveRecord :finder_sql, :counter_sql, :before_add, :after_add, :before_remove, :after_remove, :extend, :readonly, - :validate + :validate, :parameterize ] def create_has_many_reflection(association_id, options, &extension) diff --git a/activerecord/test/cases/associations_test.rb b/activerecord/test/cases/associations_test.rb index 056a294..b5da727 100644 --- a/activerecord/test/cases/associations_test.rb +++ b/activerecord/test/cases/associations_test.rb @@ -24,6 +24,7 @@ require 'models/club' require 'models/member' require 'models/membership' require 'models/sponsor' +require 'models/basket' class AssociationsTest < ActiveRecord::TestCase fixtures :accounts, :companies, :developers, :projects, :developers_projects, @@ -84,6 +85,14 @@ class AssociationsTest < ActiveRecord::TestCase assert_equal "Natural Company", db["apple"].clients.first.name end end + + def test_has_many_parameterize_methods + Basket.has_many(:eggs, :parameterize => true) + + assert Basket.instance_methods.include?("create_eggs_params=") + assert Basket.instance_methods.include?("update_eggs_params=") + assert Basket.instance_methods.include?("process_eggs_params") + end end class AssociationProxyTest < ActiveRecord::TestCase diff --git a/activerecord/test/models/basket.rb b/activerecord/test/models/basket.rb new file mode 100644 index 0000000..f6a2a97 --- /dev/null +++ b/activerecord/test/models/basket.rb @@ -0,0 +1,3 @@ +class Basket < ActiveRecord::Base + # has_many :eggs, :parameterize => true +end diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb index ab5c7c5..b7b18a7 100644 --- a/activerecord/test/schema/schema.rb +++ b/activerecord/test/schema/schema.rb @@ -51,6 +51,10 @@ ActiveRecord::Schema.define do t.integer :value end + create_table :baskets, :force => true do |t| + t.integer :capacity + end + create_table :binaries, :force => true do |t| t.binary :data end @@ -144,6 +148,11 @@ ActiveRecord::Schema.define do end add_index :edges, [:source_id, :sink_id], :unique => true, :name => 'unique_edge_index' + create_table :eggs, :force => true do |t| + t.integer :basket_id + t.string :grade + t.string :size + end create_table :entrants, :force => true do |t| t.string :name, :null => false -- 1.6.0