views:

155

answers:

1

Hello,

I have two tables Users (name, email, password, instance_id, etc...) example: james bond, [email protected], 1 Instance (id, domain) example: 1, abc.com

Through out the application I want to make sure James Bond only sees data that is assigned to his instance = 1

So if I have a books table with (name, desc, instance_id), he only sees his instance's books.

I'm told CanCan is the way to go for this but I don't see how to make something set globally like the above, it seems more role based like admin, moderator, etc... Which I'll need but at a level lower than the data rules mentioned above.

Thoughts?

+2  A: 

Hi,

you could try using scopes like:

class Books < ActiveRecord::Base
# .... code ....
scope :personal, proc {|user| where(:instance_id => user.instance_id) }
# .... code ...
end

Now you can do:

@personal_books = Books.personal(@user)

you can read more about scopes here: http://www.railsdispatch.com/posts/rails-3-makes-life-better (scroll down a little bit)

Another way is to make an association like

User has_many Books through Instance

Then you'd have an additional legacy table mapping user to books over their instance. It's an n:m relation. So a book could belong to multiple instances.

It would look like this:

User Table:

Users (name, email, password, instance_id, etc...)

Book Table:

Books (name, desc) # no more instance_id !

Mapping Table:

Assignments (instance_id, book_id)

And your Models would look like:

class Assignment < ActiveRecord::Base
  belongs_to :book      # foreign key - book_id
  belongs_to :instance  # foreign key - instance_id
end

class Instance < ActiveRecord::Base
  has_many :assignments
  has_many :books, :through => :assignments
end

class Books < ActiveRecord::Base
  has_many :assignments
  has_many :users, :through => :assignments
end

class User < ActiveRecord::Base
  belongs_to :instance
end

The code to get all books of an user's instance would look like:

@user       = User.find(:first)
@books      = @user.instance.books.find(:all)

(I recommend you to read http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html )

Edit

You could try this if a book always belongs to only one instance:

class User < ActiveRecord::Base
  belongs_to :instance
end


class Instance < ActiveRecord::Base
  has_many :users
  has_many :books
end


class Books < ActiveRecord::Base
  belongs_to :instance
end

So you grab a user's books like:

@user.instance.books.find(:all)
sled
Thanks, but I curious why use an assignments table, that would end up being a big database if every table needs an assignments table to map to the instance table. Why not just add instance_id to all records in the DB?
AnApprentice
Because you would end up having lots of duplicates in your database. A book is a "unique" object and can belong to many instances, right? So you should have only one entry for the book. But many instances can have access to this book right? So you should have an extra table telling which instances have access to certain books. This is called a many-to-many relationship or n:m relationship.
sled
Sled, a book only belongs to 1 instance which is why I don't know if the assignment table is the way to go.
AnApprentice
hi, I've edited my answer and added another possible solution
sled
Thanks but @user.books.find(:all) errors
AnApprentice
sorry my second example was wrong, I fixed it. It was too late yesterday ;)
sled