I generally agree with your solution and I would do the same, i.e. create a separate model called Share, even though it looks like a RDBMS-like solution.
But let's step back and review the available options.
First of all, consider the relations of your models. Draw them on a piece of paper and note the type of relations and their associations (belongs to, has one, has many, has many through or has_and_belongs_to_many). Perfect reference for the associations in rails is http://guides.rubyonrails.org/association_basics.html. Take into account that Mongoid also offers embedded_in/embeds_many type of relations.
In your case the relations would be: User (1..N) Boards for owning, User (N..N) Boards for sharing.
The hint to decide whether to use has_many, has_and_belongs_to_many or embeds_many is whether or not the subordinate model represents semantically embedded type of relation and is not connected with other models than its parent. It it is, use embeds_many, otherwise use has_many or has_and_belongs_to_many.
The hint to decide whether to use has_many :through or has_and_belongs_to_many is whether you are going to add more data to a linking model (Share in your case).
has_and_belongs_to_many in mongoid is doing without creation of a linking model, i.e. board_ids would be kept as an array in the User model and user_ids would be kept as an array in the Board model.
The reason to not use HABTM in your case is simple. You have two relations between your User and Board models (sharing and owning), you would have difficulty in figuring out what expression like user.boards
means (shared boards or owned boards). I don't know of an easy way to separate these two kinds of relations without use of a third model (Share) as you proposed in comments (using :as
, etc.)
You can also manually keep the ids of boards in your user model, like this:
class User
include Mongoid::Document
field :name
key :shared_board_ids, Array, :index => true
key :owned_board_ids, Array, :index => true
def shared_boards
Board.find shared_board_ids
end
# ...
end
However, difficulties in this case arise pretty fast. You have to manually destroy all board references from the User model when you destroy a board. If you keep a sharing_user_ids in your Board model, you have redundancy and another set of difficulties.
So, yes, I would recommend creating a separate Share model, as I show below.
class User
include Mongoid::Document
field :name
has_many :shares
has_many :boards
end
class Board
include Mongoid::Document
field :title
has_many :shares
belongs_to :user
end
class Share
include Mongoid::Document
belongs_to :user
belongs_to :board
end
As of permissions, CanCan is simple, but it is doing just fine. Notice a difference between terms authentication (which checks the authenticity of a user, in other words checks that the user is really who he claims he is - normally using password) and authorization (which checks the rights of the user). Authentication is handled by gems like Authlogic, Warden (and Devise based on Warden), Sorcery. Authorization is handled by Declarative_authorization or CanCan.
You're currently working on the User model within ruby as you look down you code you can see
def function
end
That creates a function that exists within the User class, so in theory from most anywhere else in your application you could do User.some_function, you only use self.some_function from within the class.
There isn't any difference between using User.encrypt and self.encrypt except that its safer, self.function means only look inside the current class.
I think you're probably getting attributes and functions mixed up because you're not seeing the () at the end of function calls, you don't actually use those in ruby unless you passing parameters to the function.
Where you're mentioning username, password, email etc those are fields associated with the database and are attributes.
The concept to understand here is that the User model represents the association with the underlying database, you can(as you have there) add extra functionality to ensure the quality of the data going in for example:
before_create :create_remember_token
That means that if ANYWHERE within you application you create a new user the model calls that function as part of the process of creating the record. Essentially by building functionality into models you can ensure that all data going into the database is treated in the same way.
Best Answer
This is what a conventional rails controller would look like:
Controllers should map to resources, and your controller is returning a list of heroes. Hence,
HeroesController#index
. All the finding stuff goes in the model.