On 29 Jul 2006 20:04:41 -0000, Kevin Olbrich <[EMAIL PROTECTED]> wrote:

On Saturday, July 29, 2006, at 1:29 PM, Daniel N wrote:
>On 7/27/06, Jeremy Kemper < [EMAIL PROTECTED]> wrote:
>>
>> On Jul 26, 2006, at 6:06 AM, Daniel N wrote:
>> > I've had a crack at this one and it is as I feared.
>> >
>> > If I define the restrict association first, then the destroy chain
>> > is halted and all is well.  But if I have an association where
>> > a :dependent => :destroy is declared before the association
>> > with :restrict then the first association is destroyed before the
>> > destroy chain is halted.
>>
>> You can wrap the destroy method to leapfrog the callback chain.
>>
>> associations.rb, configure_dependency_*
>>
>>    case reflection.options[:dependent]
>>      when :restrict
>>        class_eval <<-end_eval
>>          def destroy_with_has_many_#{ reflection.name}
>>            unless #{reflection.name}.blank?
>>              raise DestroyRestricted.new(self, #
>> { reflection.name.inspect})
>>            end
>>          end
>>
>>          alias_method_chain :destroy, "has_many_#{reflection.name}"
>>        end_eval
>>      # ...
>>    end
>>
>>
>> base.rb
>>
>>    module ActiveRecord
>>      class DestroyRestricted < ActiveRecordError
>>        def initialize(model, by)
>>          super "#{model.class.name} #{model.id} destroy restricted by
>> #{by}"
>>        end
>>      end
>>    end
>>
>>
>> > I have taken my first real plunge into the rails source and found a
>> > number of places where I thought a transaction might go to prevent
>> > this but to no avail.  Actually my head is spinning a bit trying to
>> > put all the pieces of active_record together.
>> >
>> > For this to work I think I need to put a transaction around the
>> > entire destroy chain, but I have no idea how to do this.
>> >
>> > Any pointers anyone could give would be great.
>>
>> destroy and its callbacks are wrapped in a single transaction (see
>> transactions.rb) so you can raise an exception to rollback.
>>
>>
>> example:
>>
>>    class ParentController < ApplicationController
>>      def destroy
>>        @parent.destroy
>>        redirect_to parent_url(@parent)
>>      rescue ActiveRecord::DestroyRestricted => restricted
>>        flash[:error] = restricted.message
>>        redirect_to :back
>>      end
>>    end
>>
>>
>> Best,
>> jeremy
>> _______________________________________________
>> Rails-core mailing list
>> Rails-core@lists.rubyonrails.org
>> http://lists.rubyonrails.org/mailman/listinfo/rails-core
>>
>
>Thanx Jeremy.  This looks very different to what I had in mind.   Lots
>better :)
>
>I'll get into trying to get this to work.
>
>Just a thought tho.  By raising an exception, this would put destroy into a
>different category, this should perhaps be destroy! to fit with the other
>methods that raise errors.
>
>Would including an exception into the destory method mean that it would
>break exisitng code?  I guess you would only need to use a rescue if you
>have declared a relationship as rectricted.  I'll have a go anyway and see
>what ppl think.
>
>Thanx for you help
>
>Cheers
>
>
>_______________________________________________
>Rails-core mailing list
> Rails-core@lists.rubyonrails.org
>http://lists.rubyonrails.org/mailman/listinfo/rails-core
>

Wouldn't it make sense to have it call a function like 'can_destroy?'
before trying to do the work?  Have that function recursively call
itself on all the child objects, and then only return true if all
dependent objects can be destroyed.

If can_destroy? returns false, then... don't destroy it.

It might be a little more robust than relying on exceptions, since it
will test everything before trying to destroy anything.


_Kevin
www.sciwerks.com

--
Posted with http://DevLists.com.  Sign up and save your mailbox.
_______________________________________________
Rails-core mailing list
Rails-core@lists.rubyonrails.org
http://lists.rubyonrails.org/mailman/listinfo/rails-core

Thanx for you help with this guys.

I thought it was about time I posted something for some feedback.  (And since I'm not sure about posting a patch to the rails site!)

I've attached the diff file for active_record with :dependent => :restrict

I ended up taking the suggestions and putting them together.  There is a restricted? instance method for AR.  This check first order associations only.  I thought about having it check nth order associations but this could be huge.  To do this all objects from every association, and associations associations would need to be loaded potentially.  Or at least until a restricted one is detected.

Even if this goes no further than this it has been good fun.  Understanding alias_method_chain was worth it all by itself.

Thanx again for you help.  Please if you get the chance have a look.  I hope it's not too terrible.

Cheers

Daniel

Attachment: restrict.diff
Description: Binary data

_______________________________________________
Rails-core mailing list
Rails-core@lists.rubyonrails.org
http://lists.rubyonrails.org/mailman/listinfo/rails-core

Reply via email to