Forum: Ruby on Rails How to get more informations about an association at runtime

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Joshua M. (Guest)
on 2007-03-18 11:49
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:

[code=ruby]class Member < ActiveRecord::Base
  has_and_belongs_to_many :preferred_music_styles,
    :class_name => 'MusicStyle',
    :join_table => 'members_have_preferred_music_styles'
end
[/code]

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

[code=rhtml]<%= form.checkboxes :preferred_music_styles %>[/code]

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. :-)

Thanks
Josh
Xavier N. (Guest)
on 2007-03-18 12:08
(Received via mailing list)
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. :-)

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
Joshua M. (Guest)
on 2007-03-18 15:17
> The key is
>
>    model.class.reflect_on_association(association)

Thanks a lot, that's very helpful. :-)
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?
Xavier N. (Guest)
on 2007-03-18 17:01
(Received via mailing list)
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. :-)
> 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
Joshua M. (Guest)
on 2007-03-18 20:08
> 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?(r)
      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?
Joshua M. (Guest)
on 2007-03-18 20:30
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?
Xavier N. (Guest)
on 2007-03-22 12:56
(Received via mailing list)
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
Joshua M. (Guest)
on 2007-03-24 23:35
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...?
This topic is locked and can not be replied to.