please someone help with this active record question! its driving me crazy

Quoting Jeremy McAnally <jeremymcanally@gmail.com>:

Hmm. Again, not trying this in a console or anything, but off the top of my head, you could try:

@avatars = @user.admireds.map {|user| user.avatar}

If this works, a more compact form that may work is:

@avatars = @user.admireds.map(&:avatar)

HTH,   Jeffrey

It is not out moded. Those two constructs are used in different
scenarios.

I think that 99% is way overstated.

HABTM works just fine for cases where there are no attributes needed in the association. In my experience, that's probably 90% of the time.

What's deprecated is push_with_attributes, NOT HABTM. If you need what Josh calls a "rich association" then, yes, HMT is the way to model it.

In fact HABTM got a little love in Rails 2.0 with the new fixture support which was included from the rathole plugin

http://ryandaigle.com/articles/2007/10/26/what-s-new-in-edge-rails-fixtures-just-got-a-whole-lot-easier

You can now use symbolic names for HABTM attributes and the join table will automatically be populated.

I can honestly say that in 99% of cases where I _would_ use HABTM, I use HM:T because I can almost guarantee that I will be attaching extra data to the relationship OR I will want to fetch all the relationships separately (for example, I want to see all book selections for a bookstore or something).

Perhaps it's the work that I've been doing and have always done, but that's the case that I've found myself in.

--Jeremy

Please don’t confuse the newbies with your opinions. It is your wish to follow a speculative design in your projects. Newbies need guidelines to follow for a given situation.

This has basically degenerated into a stupid pissing match.

This is all opinion. You could easily do the same thing we're talking about here with raw MySQL drivers and regular Ruby classes, but AR and habtm or hm:t is a better solution. I was merely sharing what I've learned to be best practice and what has been deemed less than best practice by myself and others.

As for "speculative design," it's not "speculative" if one is simply thinking ahead. Going about software without doing that is what leads to "refactoring" that are actually just fixing your stupid mistakes because you didn't think when you were writing code. If you think that implementing something that I can nearly always expect to use is speculative, one could say that any abstraction is speculative. "I'll probably need to share this piece of ERb so I'll push it into a partial" or "I'll probably be adding a lot of different types of data to this collection so it might be better to make it a Hash rather than an Array so I can get at it by key" are both, by your definition, statements of speculative design but are sound design decisions to make. Surely you can't contend that thinking ahead isn't a good idea?

As for this thread, I think we're done here. My HM:T code worked for him, a newbie has been helped, problem solved.

--Jeremy

Is the .map method kinda like a for loop?

Quoting Dave Lynam <dlynam@gmail.com>:

Is the .map method kinda like a for loop?

Yes, and more. It iterates through all elements in the object and returns a new array with the return value of the block.

> @avatars = @user.admireds.map {|user| user.avatar}

This example sets @avatars to the value of avatar for every element in @user.admireds. For a block as simple as this, the following will probably do the same thing.

@avatars = @user.admireds.map(&:avatar)

I saw this usage on a Web page somewhere and use it regularly, but I don't know Ruby well enough to understand exactly what it means.

HTH,   Jeffrey

@avatars = @user.admireds.map(&:avatar)

I saw this usage on a Web page somewhere and use it regularly, but I
don't know Ruby well enough to understand exactly what it means.

It's a shortcut. The & tells ruby that the parameter being passed
should be used as the block to this method. ruby calls to_proc on it
(in this case :avatar) to make sure it gets a proc. Symbol#to_proc creates a proc which when given an object calls the
named method on it

Fred

I think this code is calling the .avatar for each user.admireds object though. And that method is undefined for that class. I dont think this works. What about doing something like: @avatars = Avatar.find(:all).select {|avatar| avatar.user_id == @user.admireds } This doesnt work though b/c it doesnt iterate through the @user.admireds. This is the problem, I need to do two iterations and make comparisons with each. I'm just not sure how to do this.

I usually use its synonym - collect. To me, that better describes the output. But that's just my preference.

///ark

Oh, okay. You could do this then (I think):

  @avatars = @user.admireds.map{|adm| Avatar.find_by_user_id(adm.id)}

Why not make Avatar belong to a User (you already have user_id and would just have to put belongs_to :user in Avatar and has_one :avatar in User)?

--Jeremy

Right. I have already defined this relationship but when I do @user.admireds.avatar it says: undefined method `avatar' for Admiration:Class. so I dont think @user.admireds is creating user objects in the first place.

Oh, fool am I! You're right.

You'd need to do something like:

   @avatars = @user.admireds.map{|adm| adm.admirer.avatar }

Sorry about that! You might need to change `admirer` to `admiree` depending on which side of the relationship you're doing (sorry about not being able to scrollback and see but I'm in a bit of a hurry :)).

--Jeremy

This gives me a null object. Cause its basically saying @user.admireds.admirer.avatar...which creates a null object I guess. Im pretty confused now, Ive been tinkering with this for a while now. Any other ideas are appreciated. Thanks.

[...]

Would you explain this a bit?

@avatars is an object.

Is it a collection of users?

thanks,

Thufir

[...]

What's deprecated ispush_with_attributes, NOT HABTM. If you need what Josh calls a "rich association" then, yes, HMT is the way to model it.

In fact HABTM got a little love in Rails 2.0 with the new fixture support which was included from the rathole plugin

http://ryandaigle.com/articles/2007/10/26/what-s-new-in-edge-rails-fi

You can now use symbolic names for HABTM attributes and the join table will automatically be populated.

[...]

Am I alone in wondering what replaces push_with_attributes? This is in regards to has_many through.

thanks,

Thufir

okay so,

has_many :through replaced it. If you need attributes on yr join model, has_many :through is the way to do it. has_many :through doesn’t need push_with_attributes because it has an ActiveRecord model with proper attributes. You can just create an instance of that model and set its attributes as needed.

No, @user.admireds is a collection of User objects.

When you do #map, it iterates the collection and replaces the current index with the return value of the block. So in this case, an array of User objects is transformed into an array of avatars for those users. So, @avatars becomes an array of Avatar objects.

Read up on the #map method and it will make more sense. :slight_smile:

--Jeremy