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.
Fc582698581884352e745d1d4c64699d?d=identicon&s=25 Joshua Muheim (josh)
on 2007-03-18 10: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
7223c62b7310e164eb79c740188abbda?d=identicon&s=25 Xavier Noria (Guest)
on 2007-03-18 11:08
(Received via mailing list)
On Mar 18, 2007, at 10:49 AM, Joshua Muheim 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
Fc582698581884352e745d1d4c64699d?d=identicon&s=25 Joshua Muheim (josh)
on 2007-03-18 14: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?
7223c62b7310e164eb79c740188abbda?d=identicon&s=25 Xavier Noria (Guest)
on 2007-03-18 16:01
(Received via mailing list)
On Mar 18, 2007, at 2:17 PM, Joshua Muheim 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
Fc582698581884352e745d1d4c64699d?d=identicon&s=25 Joshua Muheim (josh)
on 2007-03-18 19: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?
Fc582698581884352e745d1d4c64699d?d=identicon&s=25 Joshua Muheim (josh)
on 2007-03-18 19: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?
7223c62b7310e164eb79c740188abbda?d=identicon&s=25 Xavier Noria (Guest)
on 2007-03-22 11:56
(Received via mailing list)
On Mar 18, 2007, at 4:00 PM, Xavier Noria 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
Fc582698581884352e745d1d4c64699d?d=identicon&s=25 Joshua Muheim (josh)
on 2007-03-24 22: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.