Craig White
2006-Apr-16 02:52 UTC
[Rails] still learning maintaining data with join tables
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
Josh Susser
2006-Apr-16 03:16 UTC
[Rails] Re: still learning maintaining data with join tables
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 :usersYou 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 > endRails 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 -- Posted via http://www.ruby-forum.com/.
Craig White
2006-Apr-16 03:29 UTC
[Rails] Re: still learning maintaining data with join tables
On Sun, 2006-04-16 at 05:16 +0200, Josh Susser wrote:> 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.---- 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
Brian V Hughes
2006-Apr-16 04:27 UTC
[Rails] Re: still learning maintaining data with join tables
On Apr 15, 2006, at 08:29 PM, Craig White wrote:> On Sun, 2006-04-16 at 05:16 +0200, Josh Susser wrote: >> 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. > ---- > 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
Craig White
2006-Apr-17 01:53 UTC
[Rails] Re: still learning maintaining data with join tables
On Sat, 2006-04-15 at 21:27 -0700, Brian V Hughes wrote:> On Apr 15, 2006, at 08:29 PM, Craig White wrote: > > On Sun, 2006-04-16 at 05:16 +0200, Josh Susser wrote: > >> 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. > > ---- > > 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/>.---- 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
Justin Forder
2006-Apr-17 11:50 UTC
[Rails] Re: still learning maintaining data with join tables
Craig White wrote:> On Sat, 2006-04-15 at 21:27 -0700, Brian V Hughes wrote: >> On Apr 15, 2006, at 08:29 PM, Craig White wrote: >>> On Sun, 2006-04-16 at 05:16 +0200, Josh Susser wrote: >>>> 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. >>> ---- >>> 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/>. > ---- > 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?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
Craig White
2006-Apr-17 14:58 UTC
[Rails] Re: still learning maintaining data with join tables
On Mon, 2006-04-17 at 12:50 +0100, Justin Forder wrote:> Craig White wrote: > > On Sat, 2006-04-15 at 21:27 -0700, Brian V Hughes wrote: > >> On Apr 15, 2006, at 08:29 PM, Craig White wrote: > >>> On Sun, 2006-04-16 at 05:16 +0200, Josh Susser wrote: > >>>> 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. > >>> ---- > >>> 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/>. > > ---- > > 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? > > 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.---- 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