Specify options with habtm


#1

Hi all

I have the following models:

class member
has_and_belongs_to_many :disc_jockeys
end

class disc_jockey
has_and_belongs_to_many :members
end

The relation table is called disc_jockeys_members and has the following
fields:

disc_jockeys_members(disc_jockey_id, member_id, status)

So far, the field status can have values like valid, invalid, locked
etc., but it is not regarded yet by Rails. So I would like to integrate
it with the standard methods.

josh $ script/console

m = Member.find(:first)
m.disc_jockeys # Returns all associated disc jockeys
m.disc_jockeys(:status => ‘valid’) # Returns associated disc jockeys with the status valid

The 4th line above should change the query

SELECT * FROM disc_jockeys LEFT JOIN disc_jockeys_members ON
disc_jockeys.id = disc_jockeys_members.disc_jockey_id WHERE
(disc_jockeys_members.member_id = 25 )

to

SELECT * FROM disc_jockeys LEFT JOIN disc_jockeys_members ON
disc_jockeys.id = disc_jockeys_members.disc_jockey_id WHERE
(disc_jockeys_members.member_id = 25 and disc_jockeys_members.status =
‘valid’)

Now my question: What ActiveRecord method do I have to edit to reach
this goal?

Thanks for help. :slight_smile:
Josh


#2

Josh,

Try this:

m = Member.find(:first)
m.disc_jockeys.find(:all, :conditions => “disc_jockeys_members.status
= ‘valid’”)

On 1/29/06, Joshua M. removed_email_address@domain.invalid wrote:

end
josh $ script/console
to
Josh


Posted via http://www.ruby-forum.com/.


Rails mailing list
removed_email_address@domain.invalid
http://lists.rubyonrails.org/mailman/listinfo/rails


Cody F.
http://www.codyfauser.com


#3

Thanks really a lot! :slight_smile:


#4

OK, so far, so good. I can access the special fields of the relationship
table now like any other attribute:

dj = m.disc_jockeys.find(:first, :conditions => “disc_jockeys_members.status = ‘invalid’”) # Invalid DJ
dj.status = ‘valid’
dj.save

This ends in a fatal error:

ActiveRecord::StaleObjectError in Djs#accept_member
Attempted to update a stale object

How can I change these attributes in the habtm relationship table?

Thanks a lot. :slight_smile:
Josh


#5

Josh,

You can’t update the attributes in the join table. You could remove
the object from the collection and then re-add it with the updated
status. Search the archives of the mailing list for more potential
solutions, as this topic has been discussed quite a bit.

On 1/29/06, Joshua M. removed_email_address@domain.invalid wrote:

Attempted to update a stale object
removed_email_address@domain.invalid
http://lists.rubyonrails.org/mailman/listinfo/rails


Cody F.
http://www.codyfauser.com


#6

Great, after hours of asking stupid questions I found out that my PDF is
corrupt and that it’s missing pages 241 to 252…
So now I found in the paper back version of the book that there’s a
push_with_attributes method that solves my problem. Thanks anyway. :slight_smile:


#7

Cody F. wrote:

You could remove
the object from the collection and then re-add it with the updated
status.
Thanks for that hint; but how can I tell Rails what status it should set
in the status field of the relationship table?

I searched the mailing lists, but didn’t really know what terms to
use… any suggestions? :slight_smile:


#8

Josh,

This page from the documentation has a lot of really good information
on associations:

Cody

On 1/31/06, Joshua M. removed_email_address@domain.invalid wrote:

http://lists.rubyonrails.org/mailman/listinfo/rails


Cody F.
http://www.codyfauser.com


#9

Thanks. I found now the following:

http://wrath.rubyonrails.org/pipermail/rails/2006-January/008369.html

I have added this code to my application.rb (just for testing purposes,
I will outsource it to lib later when it works), but the method is not
available!

josh $ script/console

m=Member.find 1
dj = DiscJockey.find 1
m.disc_jockeys.push(dj)
m.disc_jockeys.update_attributes(dj, :status => ‘xxx’)

This gives me a “NoMethodError: undefined method `update_attributes’ for
DiscJockey:Class”. I tried also this way:

class ActiveRecord::Associations::HasAndBelongsToManyAssociation
def update_attributes(record, join_attributes = {})
if record.is_a? ActiveRecord::Base
record_id = record.id
else
record_id = record
end
cols, vals = [], []
join_attributes.each do | key, val |
cols << key.to_s
vals << val
end
col_string = cols.join(’ = ?, ')
@owner.connection().update(sanitize_sql([“UPDATE #{@join_table} SET
#{col_string} = ? WHERE #{@association_class_primary_key_name} = ? AND
#{@association_foreign_key} = ?”, vals, @owner.id, record_id].flatten),
“Update Attributes”)
end
end

But it doesn’t work… What’s wrong here? I don’t have to restart the
server when I place the stuff in controller/application.rb, do I?

Greets
Josh


#10

Josh,

I just tried it, but I added:
module ActiveRecord

Pasted code

end

Then I put the code in my lib folder as “patch_habtm.rb”. Then in my
config/environment.rb file at the bottom put:
require ‘patch_habtm’.

Restart WEBrick to reload the application and give it a try.

I didn’t actually try updating, but the method is there:

i = Item.find(:first)
=> #<Item:0xb73ebecc @attributes={“name”=>“hammer”,
“created_on”=>“2006-01-29 13:08:25”, “id”=>“1”, “description”=>nil,
“created_at”=>“2006-01-29 13:08:25”}>

i.locations.respond_to?(“update_attributes”)
=> true

If you get it to work you’ll probably want to create a plugin for it
and then you can just drop it into your plugins folder in each of your
projects.

On 1/31/06, Joshua M. removed_email_address@domain.invalid wrote:

dj = DiscJockey.find 1
else
#{@association_foreign_key} = ?", vals, @owner.id, record_id].flatten),

Posted via http://www.ruby-forum.com/.


Rails mailing list
removed_email_address@domain.invalid
http://lists.rubyonrails.org/mailman/listinfo/rails


Cody F.
http://www.codyfauser.com