HMT associations with acl9
acl9
has been around for a while, but parts of it's code had bothered me for a while specially the use of has_and_belongs_to_many
, the problem was that this method did not let you have primary keys in your join table nor timestamps, etc.
Luckily rails 3.0 came out and changed the way associations work, here is how you can override your existing association and create a join model.
First create the following migrations:
class AddMissingFieldsToRolesUsers < ActiveRecord::Migration
def change
add_column :roles_users, :created_at, :datetime
add_column :roles_users, :updated_at, :datetime
add_column :roles_users, :id, :primary_key
end
end
Assuming your join table is named roles_users
and that it has no primary key nor timestamps.
class RenameRolesUsersToEnrollments < ActiveRecord::Migration
def change
rename_table :roles_users, :enrollments
end
end
We then rename our join table to enrollments
or whatever makes the most sense for you.
We can now create our join model and override acl9
association:
class Enrollment < ActiveRecord::Base
belongs_to :user
belongs_to :role
validates :user, :role, :presence => true
end
class User < ActiveRecord::Base
acts_as_authorization_subject :association_name => :roles, :join_table_name => :enrollments
has_many :enrollments
has_many :roles, :through => :enrollments
end
class Role < ActiveRecord::Base
acts_as_authorization_role :join_table_name => :enrollments
has_many :enrollments
has_many :users, :through => :enrollments
end
And there you have you can now use your join model to navigate either users or roles, you can add new fields to your join table, and add any kind of logic that your join model should need.
If you'd like to see a rails 3.2 application that is already using this checkout https://github.com/rubytij/usergroup the acl9
methods such as has_role?
, has_role!
and has_no_role!
will still work.
Written by Enrique Vidal
Related protips
3 Responses
I wasn't even aware of acl9, thanks for sharing!
It's been around for a while it has some pretty sweet functionalities.
This is a great improvement over using DB views. What I missed though was the part about linking objects and subjects without using those views.
I've made an attempt to describe how it should work at http://jimmybonney.com/articles/link_object_subject_acl9_without_database_view/ and I'd be glad to hear your thoughts about it and whether there is another / more efficient way of doing it.