How to get more informations about an association at runtime

Hi all

I’m working on a Custom Formbuilder. I want it to create me with a
single method call checkboxes for a given HABTM association.

My model looks like this:

class Member < ActiveRecord::Base has_and_belongs_to_many :preferred_music_styles, :class_name => 'MusicStyle', :join_table => 'members_have_preferred_music_styles' end

In my view I’d like to do the following:

<%= form.checkboxes :preferred_music_styles %>

The method checkboxes() should now create a set of checkboxes; one for
each music style.

But for doing this I have to get more informations about the
“preferred_music_styles” association:

  1. Does the association exist anyway?
  2. Is it a HABTM association anyway?
  3. If so, which class (MusicStyle) does it connect to?

I sadly have no idea how to accomplish this task. I’d be very happy if
some could give me a useful hint where to achieve this information. :slight_smile:

Thanks
Josh

On Mar 18, 2007, at 10:49 AM, Joshua M. wrote:

  1. Does the association exist anyway?
  2. Is it a HABTM association anyway?
  3. If so, which class (MusicStyle) does it connect to?

I sadly have no idea how to accomplish this task. I’d be very happy if
some could give me a useful hint where to achieve this
information. :slight_smile:

The key is

model.class.reflect_on_association(association)

Have a look at the classes

ActiveRecord::Reflection::MacroReflection
ActiveRecord::Reflection::AggregateReflection
ActiveRecord::Reflection::AssociationReflection

for API to query the association, they live in

activerecord/lib/active_record/reflection.rb

– fxn

The key is

model.class.reflect_on_association(association)

Thanks a lot, that’s very helpful. :slight_smile:
What’s the difference between @class_name=“MusicStyle” and
@klass=MusicStyle though?

I’m stuck right now with another problem:
I need to access the @member object from within my form builder method.
Using self.object_name I get “member”, but self.object returns nil. Am I
looking at the wrong place?

On Mar 18, 2007, at 2:17 PM, Joshua M. wrote:

The key is

model.class.reflect_on_association(association)

Thanks a lot, that’s very helpful. :slight_smile:
What’s the difference between @class_name=“MusicStyle” and
@klass=MusicStyle though?

In the first assignement there’s a string that holds the name of a
class. In the second one there’s a constant whose value is the very
class, that is, an instance of the class Class.

I’m stuck right now with another problem:
I need to access the @member object from within my form builder
method.
Using self.object_name I get “member”, but self.object returns nil.
Am I
looking at the wrong place?

The incantation is:

real_object = @template.instance_variable_get("@#{@object_name}")

– fxn

The incantation is:

real_object = @template.instance_variable_get("@#{@object_name}")

– fxn

I am really thankful for your help. I’ve got my method so far:

def checkboxes(assoc_name, options = {})
model = @template.instance_variable_get("@#{@object_name}")
association = model.class.reflect_on_association(assoc_name)
raise “A has_and_belongs_to_many association is needed
(#{association.macro} given)!” unless association.macro ==
:has_and_belongs_to_many
src = [] # Will hold the HTML code for a checkbox per entry
MusicStyle.find(:all).each do |r|
name_param = @object_name.to_s + ‘[’ + assoc_name.to_s + ‘_ids][]’
value_param = r.id
checked_param = model.send(assoc_name).include?®
src << # What to do here?
end
src.join
end

I don’t know if all the xxx_param vars have a correct value, but anyway
I don’t know how to create the checkbox in a clean way…

A method “check_box_tag” is not recognized by the form builder, so what
to do? I have modified the “check_box” method so it outputs some HTML,
but I don’t want to use it because I need just plain checkboxes.

What to do?

On Mar 18, 2007, at 4:00 PM, Xavier N. wrote:

I’m stuck right now with another problem:
I need to access the @member object from within my form builder
method.
Using self.object_name I get “member”, but self.object returns
nil. Am I
looking at the wrong place?

The incantation is:

real_object = @template.instance_variable_get("@#{@object_name}")

Let me add a comment to that.

The object the form builder is acting upon is not known by the form
builder itself, I see no API for that in the current implementation.
The default form builder is just a thin wrapper over regular form
helper methods, and the logic to figure that out is encapsulated there.

Form builders can optionally receive a second argument with the
object itself (passed to form helpers via :object), so the logic to
get the actual object would be

actual_object = object.nil? ?
@template.instance_variable_get("@#{object_name}") :
object

– fxn

Oh, yet another small question:

I just realized that the checkbox needs a name in the following style:

member[preferred_music_style_ids][]

But whether do I really get why the habtm-name (preferred_music_styles)
is singularized here nor do I see where to get this required form of the
name from.

At the moment I hacked it together using

name_param = @object_name.to_s + ‘[’ + assoc_name.to_s.singularize +
‘_ids][]’

(using the singularize method), but I guess this is not very clean, is
it? Or is it always just the singularized form, also when e.g. the
singular and plural forms are the same?

Well that’s interesting. Why is the object itself not mandatory and the
form could evaluate the type class of the object itself? Supplying the
type AND the object both seems a bit redundant to me…?