Bruno,

I actually did try that approach first before the one above, but found
that there are transaction interaction problems. So, for example, if I
use:

class User < ActiveRecord::Base
  before_destroy :unlink_comments

  def unlink_comments
    comments_as_author.each do |comment|
      debugger
      if comment.commentable_type == 'Program'
        comment.user_id = nil
        comment.save
      end
    end
  end
end

I get:

TypeError in UsersController#destroy

can't modify frozen hash

Using the ruby-debug, I get a little more info:

if comment.commentable_type == 'Program'
(rdb:1) p comment
#<Comment id: 22313, title: "", created_at: "2010-09-20 23:55:57",
commentable_id: 2, commentable_type: "Program", user_id: 16,
recipient_id: nil, comment: "<p>tester comment</p>", author_name: nil,
author_email: nil, author_url: nil, author_ip: "127.0.0.1",
notify_by_email: true, rating: 1, helpful_percentage: #<BigDecimal:
7f6d6e099f60,'0.0',9(18)>>
(rdb:1) next
/home/sbobrows/apps/rr/app/models/user.rb:12
if comment.commentable_type == 'Program'
(rdb:1) next
/home/sbobrows/apps/rr/app/models/user.rb:13
comment.user_id = nil
(rdb:1) next
/var/lib/gems/1.8/gems/activerecord-2.3.8/lib/active_record/
connection_adapters/abstract/database_statements.rb:139
if transaction_open && !outside_transaction?
(rdb:1) next
/var/lib/gems/1.8/gems/activerecord-2.3.8/lib/active_record/
connection_adapters/abstract/database_statements.rb:139
if transaction_open && !outside_transaction?
(rdb:1) next
/var/lib/gems/1.8/gems/activerecord-2.3.8/lib/active_record/
connection_adapters/abstract/database_statements.rb:140
transaction_open = false
(rdb:1) next
/var/lib/gems/1.8/gems/activerecord-2.3.8/lib/active_record/
connection_adapters/abstract/database_statements.rb:141
decrement_open_transactions
(rdb:1) next
/var/lib/gems/1.8/gems/activerecord-2.3.8/lib/active_record/
connection_adapters/abstract/database_statements.rb:142
if open_transactions == 0
(rdb:1) next
/var/lib/gems/1.8/gems/activerecord-2.3.8/lib/active_record/
connection_adapters/abstract/database_statements.rb:142
if open_transactions == 0
(rdb:1) next
/var/lib/gems/1.8/gems/activerecord-2.3.8/lib/active_record/
connection_adapters/abstract/database_statements.rb:143
rollback_db_transaction
(rdb:1) next
/var/lib/gems/1.8/gems/activerecord-2.3.8/lib/active_record/
connection_adapters/abstract/database_statements.rb:148
raise unless database_transaction_rollback.is_a?
(ActiveRecord::Rollback)
(rdb:1) next
/var/lib/gems/1.8/gems/activerecord-2.3.8/lib/active_record/
connection_adapters/abstract/database_statements.rb:148
raise unless database_transaction_rollback.is_a?
(ActiveRecord::Rollback)
(rdb:1) next
/var/lib/gems/1.8/gems/activerecord-2.3.8/lib/active_record/
connection_adapters/abstract/database_statements.rb:151
@transaction_joinable = last_transaction_joinable
(rdb:1) next
/var/lib/gems/1.8/gems/activerecord-2.3.8/lib/active_record/
connection_adapters/abstract/database_statements.rb:153
if outside_transaction?
(rdb:1) next
/var/lib/gems/1.8/gems/activerecord-2.3.8/lib/active_record/
connection_adapters/abstract/database_statements.rb:153
if outside_transaction?
(rdb:1) next
/var/lib/gems/1.8/gems/activerecord-2.3.8/lib/active_record/
connection_adapters/abstract/database_statements.rb:155
elsif transaction_open
(rdb:1) next
/var/lib/gems/1.8/gems/actionpack-2.3.8/lib/action_controller/
filters.rb:208
method.after(controller)
(rdb:1) next
/var/lib/gems/1.8/gems/actionpack-2.3.8/lib/action_controller/
rescue.rb:162
rescue_action(exception)
(rdb:1) next
/var/lib/gems/1.8/gems/actionpack-2.3.8/lib/action_controller/flash.rb:
152
if defined? @_flash
(rdb:1) next
/var/lib/gems/1.8/gems/actionpack-2.3.8/lib/action_controller/base.rb:
534
send_response
(rdb:1) next
/var/lib/gems/1.8/gems/actionpack-2.3.8/lib/action_controller/base.rb:
536
process_cleanup
(rdb:1) next
/var/lib/gems/1.8/gems/rack-1.1.0/lib/rack/response.rb:70
@block = block
(rdb:1) next
/var/lib/gems/1.8/gems/rack-1.1.0/lib/rack/response.rb:72
if [204, 304].include?(status.to_i)
(rdb:1) next
/var/lib/gems/1.8/gems/rack-1.1.0/lib/rack/response.rb:72
if [204, 304].include?(status.to_i)
(rdb:1) next
/var/lib/gems/1.8/gems/rack-1.1.0/lib/rack/response.rb:76
[status.to_i, header, self]
(rdb:1) next
/var/lib/gems/1.8/gems/actionpack-2.3.8/lib/action_controller/
dispatcher.rb:95
run_callbacks :after_dispatch, :enumerator => :reverse_each
(rdb:1) next
/var/lib/gems/1.8/gems/activerecord-2.3.8/lib/active_record/
connection_adapters/abstract/query_cache.rb:36
clear_query_cache
(rdb:1) next
/var/lib/gems/1.8/gems/activerecord-2.3.8/lib/active_record/
connection_adapters/abstract/query_cache.rb:37
@query_cache_enabled = old
(rdb:1) next
/var/lib/gems/1.8/gems/activerecord-2.3.8/lib/active_record/
connection_adapters/abstract/connection_pool.rb:365
unless env.key?("rack.test")
(rdb:1) next
/var/lib/gems/1.8/gems/activerecord-2.3.8/lib/active_record/
connection_adapters/abstract/connection_pool.rb:365
unless env.key?("rack.test")
(rdb:1) next
/var/lib/gems/1.8/gems/activerecord-2.3.8/lib/active_record/
connection_adapters/abstract/connection_pool.rb:366
ActiveRecord::Base.clear_active_connections!
(rdb:1) next
/var/lib/gems/1.8/gems/actionpack-2.3.8/lib/action_controller/
string_coercion.rb:26
[status, headers, UglyBody.new(body)]
(rdb:1) next
/var/lib/gems/1.8/gems/rack-1.1.0/lib/rack/head.rb:11
if env["REQUEST_METHOD"] == "HEAD"
(rdb:1) next
/var/lib/gems/1.8/gems/rack-1.1.0/lib/rack/head.rb:11
if env["REQUEST_METHOD"] == "HEAD"
(rdb:1) next
/var/lib/gems/1.8/gems/rack-1.1.0/lib/rack/head.rb:14
[status, headers, body]
(rdb:1) next
/var/lib/gems/1.8/gems/actionpack-2.3.8/lib/action_controller/session/
cookie_store.rb:101
session_data = env[ENV_SESSION_KEY]
(rdb:1) next
/var/lib/gems/1.8/gems/actionpack-2.3.8/lib/action_controller/session/
cookie_store.rb:102
options = env[ENV_SESSION_OPTIONS_KEY]
(rdb:1) next
/var/lib/gems/1.8/gems/actionpack-2.3.8/lib/action_controller/session/
cookie_store.rb:104
if !session_data.is_a?(AbstractStore::SessionHash) ||
session_data.send(:loaded?) || options[:expire_after]
(rdb:1) next
/var/lib/gems/1.8/gems/actionpack-2.3.8/lib/action_controller/session/
cookie_store.rb:104
if !session_data.is_a?(AbstractStore::SessionHash) ||
session_data.send(:loaded?) || options[:expire_after]
(rdb:1) next
/var/lib/gems/1.8/gems/actionpack-2.3.8/lib/action_controller/session/
cookie_store.rb:105
session_data.send(:load!) if session_data.is_a?
(AbstractStore::SessionHash) && !session_data.send(:loaded?)
(rdb:1) next
/var/lib/gems/1.8/gems/actionpack-2.3.8/lib/action_controller/session/
cookie_store.rb:105
session_data.send(:load!) if session_data.is_a?
(AbstractStore::SessionHash) && !session_data.send(:loaded?)
(rdb:1) next
/var/lib/gems/1.8/gems/actionpack-2.3.8/lib/action_controller/session/
cookie_store.rb:106
session_data = marshal(session_data.to_hash)
(rdb:1) next
/var/lib/gems/1.8/gems/actionpack-2.3.8/lib/action_controller/session/
cookie_store.rb:108
raise CookieOverflow if session_data.size > MAX
(rdb:1) next
/var/lib/gems/1.8/gems/actionpack-2.3.8/lib/action_controller/session/
cookie_store.rb:108
raise CookieOverflow if session_data.size > MAX
(rdb:1) next
/var/lib/gems/1.8/gems/actionpack-2.3.8/lib/action_controller/session/
cookie_store.rb:110
cookie = Hash.new
(rdb:1) next
/var/lib/gems/1.8/gems/actionpack-2.3.8/lib/action_controller/session/
cookie_store.rb:111
cookie[:value] = session_data
(rdb:1) next
/var/lib/gems/1.8/gems/actionpack-2.3.8/lib/action_controller/session/
cookie_store.rb:112
unless options[:expire_after].nil?
(rdb:1) next
/var/lib/gems/1.8/gems/actionpack-2.3.8/lib/action_controller/session/
cookie_store.rb:112
unless options[:expire_after].nil?
(rdb:1) next
/var/lib/gems/1.8/gems/actionpack-2.3.8/lib/action_controller/session/
cookie_store.rb:116
cookie = build_cookie(@key, cookie.merge(options))
(rdb:1) next
/var/lib/gems/1.8/gems/actionpack-2.3.8/lib/action_controller/session/
cookie_store.rb:117
unless headers[HTTP_SET_COOKIE].blank?
(rdb:1) next
/var/lib/gems/1.8/gems/actionpack-2.3.8/lib/action_controller/session/
cookie_store.rb:117
unless headers[HTTP_SET_COOKIE].blank?
(rdb:1) next
/var/lib/gems/1.8/gems/actionpack-2.3.8/lib/action_controller/session/
cookie_store.rb:120
headers[HTTP_SET_COOKIE] = cookie
(rdb:1) next
/var/lib/gems/1.8/gems/actionpack-2.3.8/lib/action_controller/session/
cookie_store.rb:124
[status, headers, body]
(rdb:1) next
/var/lib/gems/1.8/gems/rack-1.1.0/lib/rack/lock.rb:13
env[FLAG] = old
(rdb:1) next
/var/lib/gems/1.8/gems/actionpack-2.3.8/lib/action_controller/
reloader.rb:47
[status, headers, BodyWrapper.new(body, lock)]
(rdb:1) next
/var/lib/gems/1.8/gems/rails-2.3.8/lib/rails/rack/log_tailer.rb:18
tail_log
(rdb:1) next

Anyway, this led me to some research that said to reload the target
record, so here's the modified version:

  def unlink_comments
    comments_as_author.each do |comment|
      debugger
      comment.reload
      if comment.commentable_type == 'Program'
        comment.user_id = nil
        comment.save
      end
    end
  end

But still no luck.

if comment.commentable_type == 'Program'
(rdb:26) p comment
#<Comment id: 22313, title: "", created_at: "2010-09-20 23:55:57",
commentable_id: 2, commentable_type: "Program", user_id: 16,
recipient_id: nil, comment: "<p>tester comment</p>", author_name: nil,
author_email: nil, author_url: nil, author_ip: "127.0.0.1",
notify_by_email: true, rating: 1, helpful_percentage: #<BigDecimal:
7f6d6dc6fb38,'0.0',9(18)>>
(rdb:26) next
/var/lib/gems/1.8/gems/activerecord-2.3.8/lib/active_record/
connection_adapters/abstract/database_statements.rb:139
if transaction_open && !outside_transaction?
(rdb:26) p comment
NameError Exception: undefined local variable or method `comment' for
#<ActiveRecord::ConnectionAdapters::SQLite3Adapter:0x7f6d6e042d28>
(rdb:26) next
/var/lib/gems/1.8/gems/activerecord-2.3.8/lib/active_record/
connection_adapters/abstract/database_statements.rb:139
if transaction_open && !outside_transaction?

I found the Rails doc lacking in enough detail to help me out here.
What I'm guessing is that it's kind of like a mutating table error
with Oracle database triggers: you can't use a callback to modify a
table that is in the process of being modified by the encompassing
transaction.

Anyway, I gravitated toward the observer solution, because it seemed
that the observer logic was executed a step ahead of the association
callback that tries to delete the child comment records.

Thanks,
Steve


On Sep 19, 9:50 pm, Bruno Bornsztein <[email protected]>
wrote:
> Couldn't you just add a :before_destroy filter to User?
>
> class User < ActiveRecord::Base
>
>   before_destroy :unlink_comments
>
>   def unlink_comments
>     comments.each do |comment|
>       comment.author_name = comment.user.login
>       comment.author_email = comment.user.email
>       comment.user_id = nil
>       comment.save
>     end
>   end
>
> end
>
> (Note: haven't tried this code myself)

-- 
You received this message because you are subscribed to the Google Groups 
"CommunityEngine" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/communityengine?hl=en.

Reply via email to