Rails Devise Conditional authentication_keys - ruby-on-rails-3

Is there any way of making the authentication_keys configuration conditional depending on the user type?
For instance in my User model I have two different user, standard user and student, defined by the value of a bitmask attribute. I want to authenticate Students on the basis of username and school_id. Standard users don't have to have a value for school_id. In order to accommodate this I have two types of login screens, one for students and another for standard users. The student login screen has a hidden school_id field that authenticates them to their school.
In my devise configuration file I have:
config.authentication_keys = [ :username, :school_id ]
However with this setup standard users are unable to login, my guess is that it's expecting a school_id for all Users being authenticated. Is it possible to make the authentication keys conditional? Or give an allow_blank option for school_id? I want to be able to keep standard users and students in the same model.

Yes, simply do in your models:
class User < ActiveRecord::Base
devise :database_authenticatable, authentication_keys: [:username]
end
class Student < ActiveRecord::Base
devise :database_authenticatable, authentication_keys: [:username, :student_id]
end

Related

Get relation of a collection in rails

So simple but can't find how to do it in rails. I have a specific active record collection of users. Something like users = User.where(blabla). Given this collection is there a simple way to get all posts that those users have? Similar to User.posts, only for all users in that collection.
Post belongs_to User, User has_many posts.
Thanks!
Assuming that your Post model has a user_id with an association called "user", you can do something like this:
Post.where(user_id: User.where(blablah))
or
Post.joins(:user).where(users: {<user conditions>})
You'll need to be able to use the Hash form for the user conditions to use the second option. For example:
Post.joins(:user).where(users: {role: 'member'})
If your users query is more complex, you can create a scope for it:
class User < ApplicationRecord
scope :special, -> { where(< user conditions go here>) }
end
And then merge it with the Post query:
Post.joins(:user).merge(User.special)

Get Users with an attribute for each Group?

My models: User, Group, and Membership. Users can have many groups through memberships, and vice-versa. I want to create a tool for website admins that produces a large table with the following specification:
Every row represents a user,
Every column represents a group,
In each cell of the table there is a boolean indicating whether the user belongs to the group.
What would be the best way to do this? Is it possible to write a single SQL query that achieves it (i.e. User.find_by_sql)? If not, how else?
p.s. I actually need a bit more than this (I need two columns per group, the first one indicating membership, and the second one counting how many meetings the user has attended in that group, but this involves the Meeting model, so I'll leave that for later.
Assuming that you're asking about the backend methodology not the data visualization aspect most of what JuanM. said is correct. One thing I would recommend is avoid writing his 'get_groups' method and just set up a 'has many through' relationship between users in groups. To do so put
class User < ActiveRecord::Base
has_many :memberships
has_many :groups, through: :memberships
end
In your Users model and vice versa in your Groups model (assuming memberships 'belongs_to' both). Then you'll have a '.groups' method on any User instance and a '.users' method on any Group instance
This would be my approach:
Write a function that returns if the user belongs to a group passed by parameter. Get all the groups from a user. In your user.rb model you can add this method get_groups to retrieve all groups from the user and then a method is_in(group). See code below:
class User < ActiveRecord::Base
#validations, some other stuff
has_many :memberships
#this method stores all the group-ids of the user in an array
def get_groups
myGroups = []
memberships.each do |membership|
membership.groups.each do |group|
myGroups << group.id
end
end
return myGroups
end
#this method receive a Group object and return true if the user belongs to that group
def is_in(group)
groups = get_groups
return groups.include?(group.id)
end
Then in your view or controller you can work as follow:
#the columns of the table
groups = Group.all
#iterating all users
User.all.each do |user|
#each user has to see if it belongs to each group in the groups table
groups.each do |group|
#the boolean value you display in a cell
value = user.is_in(group)
end
end

Remove Redundant fields in two associated Mongoid Models

In my omniauth & omniauth-identity based app I came across the follwoing issue:
There are three tables that manage Userdata:
# Stores User data _not_ authentication data
class User
include Mongoid::Document
has_many :identities
field :email, type: String
end
# Stores Authentication data (i.e. Facebook)
class Identity
include Mongoid::Document
belongs_to :user
end
# Stores Authentication data for omniauth-identity
class LocalIdentity < Identity
include OmniAuth::Identity::Models::Mongoid
field :email, type: String
end
The issue is now that I have duplicated the email-field in LocalIdentity. So whenever a user changes his email-address in the User model I need to synchronize the email address. This seems trivial at first but can get real messy as soon as there are more fields involved etc.
So my question is: Is there a way to remove the redundance between User and LocalIdentity?
While pondering about a solution i came to the following conclusions:
Multi Inheritance isn't supported so LocalIdentity < Identity, User won't work
Having a LocalIdentity embedded in every User and
write-trough the values won't work b/c validations wouldn't work

Rails conditional validation based on polymorphic type

I am working with a Rails polymorphic inheritance configuration - I have the following setup:
User < ActiveRecord::Base
belongs_to :rolable, :polymorphic => true
Student < ActiveRecord::Base
has_one :user, :as => :rolable
accepts_nested_attributes_for :user
Teacher < ActiveRecord::Base
has_one :user, :as => :rolable
accepts_nested_attributes_for :user
I want to be able to capture email address for teachers and a username for students (who won't typically have an email address). I defined those as attributes of the User model, but now I'm stuck when I try to do validations for Student and Teacher. I didn't define them in their respective models because I'm using Devise and there will be other user types. Abstracting what is currently type to a Role pattern isn't a good fit for my particular scenario either.
Since username and email are properties of User what I basically want to do is check if the rolable_type field from the polymorphic relationship is type student and if so, make username required and email not, but in the new method that property isn't set. However Rails 'knows' this is a Student, so it feels like there's some way to check the instance type. The closest link I've found to what I'm shooting for is the third comment to the accepted answer in this question: How to apply different validation rule according to polymorphic association type (Rails)?, but I'm having trouble getting the method_missing syntax correct as I'm not experienced with metaprogramming. Am I on the right track with this? Or is there a simpler way? Or should I move the properties to the polymorphic models instead?

How to test the membership in a many-to-many relation in Rails3

For example, one user has joined many group; and one group has many user members. Now I get a user object and a group object, I want to know whether this user is a member of this group.
I can see some methods, but still wandering whether there is a better way?
So, if i understand your question, what you have is something like:
class User < ActiveRecord::Base
has_many :groups, :though => :user_members
class Group < ActiveRecord::Base
has_many :users, :though => :user_members
And you want to know if a user is a member of a specific group.
So, given something like:
u = User.first
g = Group.first
Just do:
u.groups.include? g
Thats all there is to it!
ian.
ipd's way is fine, another more Rails oriented way to do it is :
u.groups.exists?(g)