Rails devise gem and user groups - ruby-on-rails

I'm using rails devise gem for users authentification, but now for my shop i must introduce user groups for discont's, special prices, etc. How to do this with devise? Note that this is one/many-to-many, becouse every user can have many groups, and every group some users.
Also when user is registering i't group must be for example 1.
Devise has "closed" controller (not as in authlogic). That is trouble also.
def create
super
group = Group.find_by_name("newuser")
user_group = UserGroup.create
user_group.user_id = current_user.id
user_group.group_id = group.group_id
user_group.save
end

This doesn't necessarily have to be integrated with Devise unless I'm reading your question wrong. Just create a Group model describing the attributes of a group, and a UserGroup join model:
class UserGroup < ActiveRecord::Base
belongs_to :user
belongs_to :group
end
class User < ActiveRecord::Base
has_many :user_groups
has_many :groups, :through => :user_groups
# attr_accessible :user_id, :group_id
end
class Group < ActiveRecord::Base
has_many :user_groups
has_many :users, :through => :user_groups
end
As for the closed controller problem, you can lift the Devise controller into your application, or create a new controller which inherits from it and thus override the methods. Read more from their link GitHub page here.
Edit: I think you are approaching this from the wrong angle. You needn't do anything from within Devise's controllers, but rather add a before_save callback to your User model.
class User < ActiveRecord::Base
before_save(:on => :create) :assign_default_group
# Other model stuff here
private
def assign_default_group
# This automatically creates the UserGroup record
self.groups << Group.find_by_name("User")
end
end

Related

creating an association and scoping

I read "Multitenancy with Rails" by Ryan Bigg and I'm creating a multi-tenant application using Ruby on Rails.
I make two models, Tenant and User.
Tenant has many User, User belongs to Tenant.
To associate these models, I made this file,
active_record_extensions.rb
ActiveRecord::Base.class_eval do
def self.scoped_to_tenant
belongs_to :tenant
association_name = self.to_s.downcase.pluralize
Tenant.has_many association_name.to_sym, class_name: self.to_s
end
end
and add "scoped_to_tenant" to User.rb
class User < ActiveRecord::Base
scoped_to_tenant
end
When I want to get all users of one Tenant(id=1), I can get it by these code.
Tenant.find(1).users
The question is, what is the difference between I write
belongs_to :tenant
to User.rb and use scoped_to_tenant method ?
In both case, Tenant.rb is this.
Tenant.rb < ActiveRecord::Base
has_many :users
end
Thank you for answer.
I may get English wrong, so please tell me if you can't understand something.
A call to scoped_to_tenant method call the method belongs_to for you and add the many association to Tenant.
This is same as doing this :
# app/model/user.rb
class User < ActiveRecord::Base
belongs_to :tenant
end
# app/model/tenant.rb
class Tenant < ActiveRecord::Base
has_many :users
end
The benefit of the scoped_to_tenant is that you don't care about adding has_many relationship to Tenant model.
If you only have one model to associate with Tenant, you don't need this extension.

ActiveRecord won't build the right class using STI

I'm using single table inheritance in my application and running into problems building inherited users from an ancestor. For instance, with the following setup:
class School < ActiveRecord::Base
has_many :users
end
class User < ActiveRecord::Base
attr_accessible :type #etc...
belongs_to :school
end
Class Instructor < User
attr_accessible :terms_of_service
validates :terms_of_service, :acceptance => true
end
Class Student < User
end
How can I build either a instructor or student record from an instance of School? Attempting something like School.first.instructors.build(....) gives me a new User instance only and I won't have access to instructor specific fields such as terms_of_service causing errors later down the rode when generating instructor-specific forms, building from console will give me an mass-assignment error (as it's trying to create a User record rather than an Instructor record as specified). I gave the example of School, but there are a few other associations that I would like to inherit from the User table so I don't have to repeat code or fields in the database. Am I having this problem because associations can not be shared in an STI setup?
You should specify instructors explicitly
class School < ActiveRecord::Base
has_many :users
has_many :instructors,:class_name => 'Instructor', :foreign_key => 'user_id'
end
And what else:
class School < ActiveRecord::Base
has_many :users
has_many :instructors
end
class Instructor < User
attr_accessible :terms_of_service # let it be at the first place. :)
validates :terms_of_service, :acceptance => true
end
OK it seems part of the problem stemmed from having the old users association inside of my School model. Removing that and adding the associations for students and instructors individually worked.
Updated School.rb:
class School < ActiveRecord::Base
#removed:
#has_many :users this line was causing problems
#added
has_many :instructors
has_many :students
end

Rails Mountable Engine with CanCan

I'm working on a blog engine and I wan't to setup cancan. I found some ways to do it:
forem doest the thing by adding an admin field in the host user model, but having multiple roles would require many fields, and that is definitely not the way to do it
I saw some exames like this but to do it I would need to have my host app user model having has_many relations to my engine models, like this
class User < ActiveRecord::Base
attr_accessible :name
has_many Blogcms::RoleUser
has_many Blogcms::Role, :through => Blogcms::RoleUser
end
I don't really know if this is the right way to do it, but this wont work because beeing a isolated engine the engine models will be invisible
has someone tried this?
sorry for my english
EDIT
I found a way around, not having to search through the User model and just setting up the relations in my Role model
module Blogcms
class Role < ActiveRecord::Base
has_many :role_user
has_many :user, :class_name => Blogcms.user_class, :through => :role_user
attr_accessible :name
# Return all the roles for a user
def self.roles_for_user(user)
joins(:user).where('users.id' => user.id)
end
end
end
like that my roles_for_user methods returns all the roles for a user
I found a way around, not having to search through the User model and just setting up the relations in my Role model
module Blogcms
class Role < ActiveRecord::Base
has_many :role_user
has_many :user, :class_name => Blogcms.user_class, :through => :role_user
attr_accessible :name
# Return all the roles for a user
def self.roles_for_user(user)
joins(:user).where('users.id' => user.id)
end
end
end
like that my roles_for_user methods returns all the roles for a user

Create 'groups' that users can join, what would be a good approach?

I want to build "groups" that users can join,
The flow of steps and things needed is in my head but the code to build this lacks some bit since I'm still learning rails. I would like to ask some advice on your ideas best practice of what would be needed to accomplish below:
You can create a group with a name 'test'
You automatically join the group test, other users can join to
If want to see a list of the users joined my group 'test'
Im thinking of creating a model sessions like
groups|name|
But then how could I store the multiple users that are in this session?
Should I make an array of the user_id's for example and make an extra column like
groups|name|user_ids ?
What would be best practice and what rails (3) methods could I use to get a very rough version of the above functionality up and running ?
From what I understand this is a many to many relationship. So you would have 3 models :
class User < AR
has_many :memberships
has_many :groups, :through => :memberships
end
class Membership < AR
belongs_to :user
belongs_to :group
end
class Group < AR
has_many :memberships
has_many :users, :through => :memberships
end
and to know what users belong to a group :
#group = Group.find_by_name("test")
#users_group = #group.users
Update
to ensure the user creating the group also belongs to it :
# in group_controller.rb
def create
#group = Group.new(params[:group])
#group.users << current_user
if #group.save
# ... etc
end
end
of course the current_user should exist/be logged in with the usual before_filter (if I remember correctly its authenticate! with devise)
Sorry i'm creating a new thread, but I am unable to comment as of my new status right now.
#charlysisto your answer for this question involves a User, Membership, and Group class. I understand the need of User and Group, but I am confused to why we would need a Membership class. If anything doesn't it make more sense to have a Groups class with Group?
class User < AR
belongs_to :group
belongs_to :groups, :through => :group
end
class Groups < AR
has_many :groups
has_many :users, :through => :group
end
class Group < AR
has_many :users
belongs_to :groups
end
What do you think?

Dynamically add/modify activerecord associations

I have what I'd think would not be a unique situation with ActiveRecord, but I can't seem to find anyone with a similar issue, so here goes:
I have a User class for users and a Roles class that defines the capabilities of the user. For ex, you could have a user with a role of 'tutor', a user with a role of 'student', and a user with a role of ['tutor', 'student']:
class User < ActiveRecord::Base
has_many :roles
end
class Role < ActiveRecord::Base
end
What I'd like to do is add activerecord associations based on roles. Clearly, a student may have many :courses, a tutor may have a :subject they teach, and both a student and tutor could have many :appointments, but it doesn't seem like adding all these associations to every User instance is the right way to go.
Subclassing User also seems wrong - I thought about doing Tutor < User and Student < User, and adding the proper associations in each subclass, but what if we have a student that is a tutor? Then we need a StudentTutor class? If more roles are added, this route seems dangerous.
I've considered doing something like:
class User < ActiveRecord::Base
protected
after_initialize do
if self.has_role?(Role::STUDENT)
has_many :courses # This does not work
else
# etc etc etc
end
end
end
But I have no idea if this is considered wrong or how I'd even make it work. What's the best method for dealing with this kind of user/role setup with associations?
I would recommend a gem for your issue. See a related SO question: Recommendation for Role Gem
I would do the following:
class User < ActiveRecord::Base
has_many :roles
end
class Role < ActiveRecord::Base
end
class Tutor < Role
has_one :subject
end
class Student < Role
has_many :courses
end

Resources