Search code examples
sqlrubysinatraruby-datamapper

DataMapper many-to-many association


At the moment I have the database model up and can populate the models with data:

   user.persons << person
    group.functions << function
    group.classificationlevels << clasfication
    user.groups << group

These are the models I am using at the moment for getting the data associated with each other:

module Core_authentication

  class User
    include DataMapper::Resource

    property :id, Serial
    property :username, String, :required => true, :unique => true  
    property :password, BCryptHash, :required => true 
    property :email, String, :format => :email_address, :required => true
    property :created_at, DateTime
    property :updated_at, DateTime

    #Creating join tables to link to group and person information
    has n, :persons, :through => Resource
    has n, :groups, :through => Resource

    def username= new_username
      super new_username.downcase
    end

  end 

  class Group
    include DataMapper::Resource

    property :id, Serial
    property :groupname, String, :required => true

    #Another jointable link group to link to functions and classification levels
    has n, :functions, :through => Resource
    has n, :classificationlevels, :through => Resource
    has n, :users, :through => Resource

    def groupname= new_group
      super new_group.downcase.capitalize!
    end
  end  

  class Person
    include DataMapper::Resource

    property :id, Serial
    property :firstname, String
    property :lastname, String, :required => true
    property :adress, String
    property :postcode, String, :length => 6, :required => true
    property :telefoon, String
    property :created_at, DateTime
    property :updated_at, DateTime

    has n, :users, :through => Resource

    def firstname= new_firstname
      super new_firstname.downcase.capitalize!
    end

    def lastname= new_lastname
      super new_lastname
    end

  end  

  class Function
    include DataMapper::Resource

    property :id, Serial
    property :name, String

    has n, :groups, :through => Resource

  end  

  class Classificationlevel
    include DataMapper::Resource

    property :id, Serial
    property :levelcode, Integer
    property :name, String

    has n, :groups, :through => Resource

  end

end

I want to get a user's groups they are a member of, and the classification level that is associated with each group.

I tried multiple ways of doing this, and also looked around on the web, but I cannot find a clear explanation on how I must do this, and so I can't get it working.


Solution

  • The documentation for Datamapper (section for "Has, and belongs to, many (Or Many-To-Many)") has some hints, here's a simplified example of your models:

    require 'sqlite3'
    require 'dm-core'
    require 'dm-sqlite-adapter'
    require 'dm-migrations'
    
    DataMapper.setup(:default, 'sqlite3:m2m.sqlite3')
    
    class User
      include DataMapper::Resource
      property :id, Serial
      has n, :persons, :through => Resource # => PersonUser
      has n, :groups, :through => Resource # => GroupPerson
    end
    
    class Group
      include DataMapper::Resource
      property :id, Serial
      has n, :functions, :through => Resource # => FunctionGroup
      has n, :classificationlevels, :through => Resource # => GroupClassificationlevel
      has n, :users, :through => Resource # => GroupUser
    end
    
    class Person
      include DataMapper::Resource
      property :id, Serial
      has n, :users, :through => Resource # => PersonUser
    end
    
    class Function
      include DataMapper::Resource
      property :id, Serial
      has n, :groups, :through => Resource # => FunctionGroup
    end
    
    class Classificationlevel
      include DataMapper::Resource
      property :id, Serial
      has n, :groups, :through => Resource # => GroupClassificationlevel
    end
    

    And an example of using them (if you put both of these snippets in a file and run them, you can see the output):

    DataMapper.finalize
    
    DataMapper.auto_migrate!
    
    user  = User.create
    group = Group.create
    
    # link them by adding to the relationship
    user.groups << group
    user.save
    
    p user.groups # => [#<Group @id=1>]