Forum: Ruby on Rails still learning maintaining data with join tables

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.
C1e5a9e9344b6d31b9df7303e6dc378a?d=identicon&s=25 Craig White (Guest)
on 2006-04-16 04:52
(Received via mailing list)
Class Role
  has_and_belongs_to_many :users
Class User
  has_and_belongs_to_many :roles
Class RolesUsers
  has_and_belongs_to_many :roles
  has_and_belongs_to_many :users

According to the logs...I'm good through here

    @roles_users = RolesUsers.find(:all,
      :conditions => ["user_id = ?", params[:users_id]] )

the next section of controller code is a problem...

    for entry in @roles_users do
      entry.destroy
    end

ActiveRecord::StatementInvalid in LoginController#save_rights
PGError: ERROR:  relation "roles_users_users" does not exist

I really expected the above to work so I am missing some piece of
fundamental understanding of how join tables work.

Anyone?

Thanks

Craig
9f0f89bbd9e1ecfbaab6584e429b7a2f?d=identicon&s=25 Josh Susser (jsusser)
on 2006-04-16 05:16
Craig White wrote:
> Class Role
>   has_and_belongs_to_many :users
> Class User
>   has_and_belongs_to_many :roles
> Class RolesUsers
>   has_and_belongs_to_many :roles
>   has_and_belongs_to_many :users

You seem to be mixing up has_and_belongs_to_many (join table) with
has_many :through (join model) associations. For habtm you don't have a
model class for the join table. If you need to manipulate the records in
the join table or store additional attributes on them, then you need to
switch to using has_many :through. If so, you'll need that model class,
but then it is just another model and doesn't need to be named the same
way join tables do.

> the next section of controller code is a problem...
>
>     for entry in @roles_users do
>       entry.destroy
>     end

Rails is confused because it's trying to work with the join table
records like they were model objects. I think you want to be iterating
on roles, not roles_users. If you want to remove an entry in the join
table, do something like

  some_user.roles.delete(some_role)

--
Josh Susser
http://blog.hasmanythrough.com
C1e5a9e9344b6d31b9df7303e6dc378a?d=identicon&s=25 Craig White (Guest)
on 2006-04-16 05:32
(Received via mailing list)
On Sun, 2006-04-16 at 05:16 +0200, Josh Susser wrote:
> has_many :through (join model) associations. For habtm you don't have a
> model class for the join table. If you need to manipulate the records in
> the join table or store additional attributes on them, then you need to
> switch to using has_many :through. If so, you'll need that model class,
> but then it is just another model and doesn't need to be named the same
> way join tables do.
----
I need to manipulate the records in the join table.
(i.e, delete/add because I can't edit them since they don't have an
primary key)

What would be the proper structure for has_many :through for the above
setup?

(I'll hold off on the delete stuff until I figure this out)

Thanks

Craig
7c4087d053eb02d099a17d91ba5e33b5?d=identicon&s=25 Brian V Hughes (Guest)
on 2006-04-16 06:30
(Received via mailing list)
On Apr 15, 2006, at 08:29 PM, Craig White wrote:
>> You seem to be mixing up has_and_belongs_to_many (join table) with
>> way join tables do.
> ----
> I need to manipulate the records in the join table.
> (i.e, delete/add because I can't edit them since they don't have an
> primary key)

What you just said here, goes against the way Rails defines model
associations. If the only thing you need to do is remove entries from
a standard join table, you can do that with a standard habtm. Check
out the habtm section on this page: <http://rails.rubyonrails.com/
classes/ActiveRecord/Associations/ClassMethods.html#M000533>. You'll
see how you can call both the delete method (for removing 1 or more
joins) and the clear method (for removing all joins), between users
and roles.

> What would be the proper structure for has_many :through for the above
> setup?

You would only use has_many :through if your roles_users table needed
to have additional columns of data, beyond the two foreign keys. If
this is the case, then you turn that join table into a "join model",
which would have a ID column, along with the two foreign keys, and
whatever other columns you needed to keep track of data relative to
the join entries. The URL that I put above also has the info for
has_many :through as does Josh's Typo blog, since he's kind of the
"has_many :through" guy. :) i recommend checking out his posts on the
topic, at <http://www.hasmanythrough.com/>.

This should also be a reminder to many posters out there, who might
be struggling with this aspect of Rails/ActiveRecord. Make sure you
take the time to learn how the various associations work and when you
should use which type of association. They are extremely powerful,
and as such, often difficult to grasp without 2 or 3 (or more ;)
reads of the documentation...

-Brian
C1e5a9e9344b6d31b9df7303e6dc378a?d=identicon&s=25 Craig White (Guest)
on 2006-04-17 03:56
(Received via mailing list)
On Sat, 2006-04-15 at 21:27 -0700, Brian V Hughes wrote:
> >>
> >> same
> classes/ActiveRecord/Associations/ClassMethods.html#M000533>. You'll
> which would have a ID column, along with the two foreign keys, and
> whatever other columns you needed to keep track of data relative to
> the join entries. The URL that I put above also has the info for
> has_many :through as does Josh's Typo blog, since he's kind of the
> "has_many :through" guy. :) i recommend checking out his posts on the
> topic, at <http://www.hasmanythrough.com/>.
----
OK - I refactored and got it all working today simply using the join
tables but removing the 'roles_users.rb' model

Life seemed to be good and I was able to get through all of the issues
of editing/deleting/adding new records to the join table and they work.

I then committed my changes to the repository and updated my live system
and find that I am now getting an error when using the join model in
controller...

The error...

Processing LoginController#user_rights (for 192.168.3.7 at 2006-04-16
18:35:04) [GET]
  Session ID: 161d2b0f800a1069937f11381201e1b7
  Parameters: {"action"=>"user_rights", "id"=>"17",
"controller"=>"login"}


NameError (uninitialized constant RolesUsers):
    /usr/lib/ruby/gems/1.8/gems/activesupport-1.3.1/lib/active_support/dependencies.rb:100:in
`const_missing'
    /usr/lib/ruby/gems/1.8/gems/activesupport-1.3.1/lib/active_support/dependencies.rb:131:in
`const_missing'
    /usr/lib/ruby/gems/1.8/gems/activesupport-1.3.1/lib/active_support/dependencies.rb:133:in
`const_missing'
    /app/controllers/login_controller.rb:73:in `user_rights'

Where the line 73 in question is...

    @roles_users = RolesUsers.find(:all,
      :conditions => ["roles_users.user_id = ?", params[:id]],
      :order => 'role_id'
      )

and just for completeness...

Class Role has_and_belongs_to_many :users
Class User has_and_belongs_to_many :roles

and there is a populated table (from migrations) called roles_users
which was populated in this fashion (in a migration)...

      User.find(:all).each { |u| u.roles << Role.find(:first,
        :conditions => ["id = ?", 3]) }

and the same 'version' works at home (though I am using Fedora 4 at home
and RHEL 4 on the production system). Both have the same version of rake
- 0.7.1 and rails 1.1.2 and I have run 'rake rails:update' on both
systems and I have verified that 'role.rb' and 'user.rb' are the same on
both systems

Clues?

Craig
Eea7ad39737b0dbf3de38874e0a6c7d8?d=identicon&s=25 Justin Forder (Guest)
on 2006-04-17 13:53
(Received via mailing list)
Craig White wrote:
>>>>>   has_and_belongs_to_many :users
>>>> same
>> see how you can call both the delete method (for removing 1 or more
>> the join entries. The URL that I put above also has the info for
> I then committed my changes to the repository and updated my live system
>
>       :conditions => ["roles_users.user_id = ?", params[:id]],
>
>       User.find(:all).each { |u| u.roles << Role.find(:first,
>         :conditions => ["id = ?", 3]) }
>
> and the same 'version' works at home (though I am using Fedora 4 at home
> and RHEL 4 on the production system). Both have the same version of rake
> - 0.7.1 and rails 1.1.2 and I have run 'rake rails:update' on both
> systems and I have verified that 'role.rb' and 'user.rb' are the same on
> both systems
>
> Clues?

You said you had removed roles_users.rb (implying that you are aiming
for straightforward HABTM, rather than using a join model), so you
shouldn't be referring to RolesUsers in your controller.

To get the Roles for a given User you should just be able to use

   @roles = @user.roles

(assuming that @user is the user with id params[:id])

If it isn't breaking on your home system, you presumably haven't removed
roles_users.rb from that.

regards

   Justin
C1e5a9e9344b6d31b9df7303e6dc378a?d=identicon&s=25 Craig White (Guest)
on 2006-04-17 17:02
(Received via mailing list)
On Mon, 2006-04-17 at 12:50 +0100, Justin Forder wrote:
> >>>>>   has_and_belongs_to_many :roles
> >>>> but then it is just another model and doesn't need to be named the
> >> classes/ActiveRecord/Associations/ClassMethods.html#M000533>. You'll
> >> whatever other columns you needed to keep track of data relative to
> >
> > "controller"=>"login"}
> >     @roles_users = RolesUsers.find(:all,
> > which was populated in this fashion (in a migration)...
> > Clues?
>
> If it isn't breaking on your home system, you presumably haven't removed
> roles_users.rb from that.
----
you are correct and I learned something about the nature of Rails...

I moved roles_users.rb into RAILS_ROOT/app/models/hold on my home system
and didn't add them to svn which is why it worked at home and not in
production. Strange...anyway, copying them into production got me
working which given the late hour of Sunday night and the prospect of
them working tomorrow on new setup early this morning seemed to be a
perfectly workable solution for the present and I can solve my riddle on
my home system.

Thanks for the diagnosis - I thought it wouldn't automatically find
models hidden in a nested folder but indeed Rails does find them.

Craig
This topic is locked and can not be replied to.