why can't I save to a join table in a migration or rake task?

where is member_role coming from?

also, the save! is not necessary, as the << method saves the data in
the join table.

Hi Chris,

Here's is the rake task version. member_role is a local variable with the value of a Role object with the title "member".

  desc "setup_roles for users."
  task :setup_roles => :environment do
    anonymous_role = Role.find_or_create_by_title('anonymous')
    member_role = Role.find_or_create_by_title('member')
    mananger_role = Role.find_or_create_by_title('manager')
    author_role = Role.find_or_create_by_title('author')
    admin_role = Role.find_or_create_by_title('admin')
    User.find(:all).each {|u| u.roles << member_role; u.save! }
    anonymous = User.find_by_login('Anonymous')
    anonymous.roles.each {|r| r.destroy }
    anonymous.roles << anonymous_role
    stephen = User.find_by_login('stephen')
    stephen.roles << admin_role
  end

I added the save! just to see if saving the object to which the collection is related would make a difference. It didn't and I should have deleted it from my example before posting the question.

After running the migration listed below and then running the rake task listed above I have just two entries in the table roles_users, one for the anonymous user and one for me. If instead I run these two commands in script/console:

member_role = Role.find_or_create_by_title('member')
User.find(:all).each {|u| u.roles << member_role }

The new entries are created in the roles_users joint table for all the users.

Here's the migration I keep running up and down:

class AddRolesUsers < ActiveRecord::Migration
  def self.up
    create_table "#{RAILS_APPLICATION_PREFIX}roles_users", :id => false, :force => true do |t|
      t.column "role_id", :integer
      t.column "user_id", :integer
    end
  end

  def self.down
    drop_table "#{RAILS_APPLICATION_PREFIX}roles_users"
    Role.delete_all
  end
end

try this

replace

User.find(:all).each {|u| u.roles << member_role }

with

User.find(:all).each do |u|
  p "#{u.roles.size}"
  u.roles << member_role
  p "#{u.roles.size}"
  p "added member role to #{u.name}"
end

and see what happens

try this

replace

User.find(:all).each {|u| u.roles << member_role }

with

User.find(:all).each do |u|
p "#{u.roles.size}"
u.roles << member_role
p "#{u.roles.size}"
p "added member role to #{u.name}"
end

and see what happens

Chris,

Thanks so much for providing another set of eyes. I took your suggestion and expanded on it. Quickly here was the problem:

  anonymous.roles.each {|r| r.destroy }

What that actually does is delete all the roles_users associations that point to the any roles the anonymous user has:

This is the command that does what I intended:

  anonymous.roles.delete_all

For anybody else that finds this email in the future here's what I put in the rake task to help me debug the problem:

  task :setup_roles => :environment do
    anonymous_role = Role.find_or_create_by_title('anonymous')
    member_role = Role.find_or_create_by_title('member')
    mananger_role = Role.find_or_create_by_title('manager')
    author_role = Role.find_or_create_by_title('author')
    admin_role = Role.find_or_create_by_title('admin')
    User.find(:all).each do |u|
      puts "\n--#{u.name}--"
      puts " roles: size: #{u.roles.size}"
      u.roles << member_role
      puts " added member role to #{u.name}: u.roles << member_role"
      puts " roles: size: :#{u.roles.size}"
    end
    puts "\n1: Checking Users for Roles:"
    User.find(:all).each do |u|
      puts "\n--#{u.name}--"
      puts " roles: size: #{u.roles.size}"
    end
    anonymous = User.find_by_login('Anonymous')
    anonymous.roles.each {|r| r.destroy } # *** this is the problem ***
    anonymous.roles << anonymous_role
    stephen = User.find_by_login('stephen')
    stephen.roles << admin_role
    puts "\n2: Checking Users for Roles:"
    User.find(:all).each do |u|
      puts "\n--#{u.name}--"
      puts " roles: size: #{u.roles.size}"
    end
  end

On the first loop I got output like this:

--Anonymous User--
  roles: size: 0
  added member role to Anonymous User: u.roles << member_role
  roles: size: :1

--Stephen Bannasch--
  roles: size: 0
  added member role to Stephen Bannasch: u.roles << member_role
  roles: size: :1

--Carolyn Staudt--
  roles: size: 0
  added member role to Carolyn Staudt: u.roles << member_role
  roles: size: :1

...

Everything still looks fine right after that:

1: Checking Users for Roles:

--Anonymous User--
  roles: size: 1

--Stephen Bannasch--
  roles: size: 1

--Carolyn Staudt--
  roles: size: 1

...

But at the end it looks like this:

2: Checking Users for Roles:

--Anonymous User--
  roles: size: 1

--Stephen Bannasch--
  roles: size: 1

--Carolyn Staudt--
  roles: size: 0

...

All the roles_users associations I made for the Users are gone.