Rails 3 - Database query on Models User and Role in a many to many condition - ruby

I have two entities. User and Role. I am using Devise and CanCan.
They are in a many to many relationship.
User has a lot of roles.
One of the roles is "Administrator". I verify if my user is an administrator using:
if (user.role? :administrator) .... #this is already implemented and working
I have to validate that never exists more than 2 administrator in the same department on the system. For that purpose I created a custom validate method:
class User < ActiveRecord::Base
validate :maximum_numbers_of_admins if self.role? :administrator
belongs_to :department
def maximum_numbers_of_admins
#Some code here
end
In that method I should count the number of Users that have role administrator (without counting myself).
I don't know how to set the :conditions of my find method to get this number.
This is the specification of the Role class:
# == Schema Information
#
# Table name: roles
#
# id :integer not null, primary key
# name :string(255)
# created_at :datetime
# updated_at :datetime
#
There is a many to many relationship between users and Roles. (Table roles_users)
Any help with that?
Thanks

It could be something along this lines:
def maximum_numbers_of_admins
if Role.find(:conditions => ['name = ?', 'Administrator']).users.count < 2
return true
else
return false
end
end

Related

Securely pass ID param in URL rails

I have a link like this: http://www.somesite.com/s/bkucoj?i=#{#client.id}.
How do I make sure, that client's id will be passed securely (hashed/encrypted), and not just naked number?
So the goal is to get something like:
http://www.somesite.com/s/bkucoj?i=f1nSbd3bH34ghfAh12lcvzD
instead of
http://www.somesite.com/s/bkucoj?i=12.
How can I achieve it?
And what's more, I would also like to ensure, that on the other end the client ID is gotten correctly
Thank you!
Probably the best way to do this would be to add an extra column (non-null, unique) to your User model, which is randomized upon the User creation.
before_create do
self.uuid = SecureRandom.uuid
end
Then you can use uuid to identify the user instead of id.
Naturally you will need to modify all your existing user when adding this column.
Implementation details
Your migration needs to have 3 parts. Firstly you need to add a uniq, nullable column uuid to users table. Then, you need to loop over your existing customers and populate this column. After it you can make the column not-nullable. It would most likely look like this:
class Blah000000000 < ActiveRecord::Migration
class User < ActiveRecord::Base
before_save { self.uuid ||= SecureRandom.uuid }
end
def up
add_column :users, :uuid, :string, unique: true
User.all.each &:save!
change_column :user, :uuid, string, unique: true, null: false
end
def down
remove_column :users, :uuid
end
end
You could add an extra parameter which is the HMAC or digital signature of the id. The recipient can verify that id has not changed.

creating a record with has_one and belongs_to

I have a User and a Team model. A user can only have one team and each team belongs to a user. I'm struggling to get the association to work both ways.
Team model:
class Team < ActiveRecord::Base
belongs_to :user
end
User model:
class User < ActiveRecord::Base
has_one :team
end
I've added a team_id column to the users table and user_id to a teams table.
I want to create a team for the user so in the console I did the following
#user = User.find_by(id: 4)
#team = #user.build_team
Which created a team with the correct user_id but the team_id for the user is still nil. What am I doing wrong?
I was going to delete this question as it's probably pretty stupid, but in case any one else gets as confused as me I found the answer here: http://ruby-on-rails.wonderhowto.com/how-to/use-one-one-association-when-using-ruby-rails-3-407824/
What I now understand is that you have a has_one relationship and the foreign key appears in the table of the Model that it 'owns'. I.e. a user has_one team so the teams table needs a user_id. The users table does not need a team_id.
You can create a new team by using
#team = #user.build_team
As I did or:
#user.team = (name: "blah", rating: "blah blah")
and then if you want to get the teams user then
#user.team
will return that object.

Sequel model over two joined tables

I have a legacy PostgreSQL database, which has a single model split into two tables, with one-to-one mapping between them.
CREATE TABLE auth_user (
id SERIAL,
username VARCHAR(30),
email VARCHAR(75),
password VARCHAR(64),
first_name VARCHAR(75),
last_name VARCHAR(75)
)
CREATE TABLE user_profile (
user_id INTEGER REFERENCES auth_User.id,
phone VARCHAR(32)
)
Unfortunately, I'm unable to change database structure.
I want to use this as a single Sequel model. Retreiving data from database works as expected:
class User < Sequel::Model
end
# Variant 1: using LEFT JOIN
#User.set_dataset DB[:auth_user].left_join(:user_profile, :user_id => :id)
# Variant 2: using two FROM tables
User.set_dataset DB[:auth_user, :user_profile]\
.where(:auth_user__id => :user_profile__user_id)
user = User[:username => "root"] # This works.
However, saving the model fails:
user.set :first_name => "John"
user.save # This fails.
If I use first variant of the dataset (with left_join) I get a "Need multiple FROM tables if updating/deleting a dataset with JOINs" error. If I use second variant, it still fails: "PG::Error: ERROR: column "phone" of relation "auth_user" does not exist LINE 1: ..."email" = 'nobody#example.org', "password" = '!', "phone"..."
Is there a way I could make Sequel seamlessly issue two UPDATE statements? (Same question holds for INSERTs, too).
You can have a Sequel model that uses a joined dataset, but there's no easy way to save such a model.
Personally, I would use a many_to_one relationship, nested attributes, and hooks for what you want:
class UserProfile < Sequel::Model(:user_profile)
end
class User < Sequel::Model(:auth_user)
many_to_one :user_profile, :key=>:id, :primary_key=>:user_id
plugin :nested_attributes
nested_attributes :user_profile
def phone
user_profile.phone
end
def phone=(v)
user_profile.phone = v
end
def user_profile
if s = super
s
else
self.user_profile_attributes = {}
super
end
end
def before_destroy
user_profile.destroy
super
end
def before_create
user_profile
super
end
def after_update
super
user_profile.save
end
end
I haven't tested that, but something like it should work. If you have problems with it, you should probably post on the sequel-talk Google Group.

Attributes passed to .build() dont show up in the query

Hope your all enjoying your hollydays.
Ive run into a pretty funny problem when trying to insert rows into a really really simple database table.
The basic idea is pretty simple. The user selects one/multiple users in a multiselect which are supposed to be added to a group.
This piece of code will insert a row into the user_group_relationships table, but the users id always
#group = Group.find(params[:group_id])
params[:newMember][:users].each do |uid|
# For debugging purposes.
puts 'Uid:'+uid
#rel = #group.user_group_relationships.build( :user_id => uid.to_i )
#rel.save
end
The user id always gets inserted as null even though it is clearly there. You can see the uid in this example is 5, so it should work.
Uid:5
...
SQL (0.3ms) INSERT INTO
"user_group_relationships"
("created_at", "group_id",
"updated_at", "user_id") VALUES
('2010-12-27 14:03:24.331303', 2,
'2010-12-27 14:03:24.331303', NULL)
Any ideas why this fails?
Looks like user_id is not attr_accessible in the UserGroupRelationship model.
You might also want to check this it may be relevant.
I think #zabba's answer is probably the one you need to look for but i would suggest a couple of extra things here.
Your "Group" and "User" models are connected to each other thru the "UserGroup" model it seems. You would have relationship
class Group < ActiveRecord::Base
has_many :user_group_relationships
has_many :users, :through => :user_group_relationships
end
class UserGroupRelationship < ActiveRecord::Base
belongs_to :group
belongs_to :user
end
In your controller
# Find the group
#group = Group.find(params[:group_id])
# For each user id, find the user and add the user_group_relationship
params[:newMember][:users].each{|u| #group.users << User.find(u) }
Read up Rails Documentation on associations and the methods generated automatically for you when associations are defined. More often than not, working with association is easier than you might think! I discover new APIs in Rails constantly! :) Good Luck!

How to make a database appear partitioned by some columns with Active::Record

Suppose a column client_id is ubiquitous through out our database, and for a given session or request, we will be 'in the context' of a client the whole time.
Is there a way to simulate having each client's data stored in a separate database, while keeping them in the same table for simpler database-management ? What I want is similar to a default scope, but since it will change for every request, it cant' be fixed at load-time.
# invoices table data
# -------------------
# id client_id amount
# 1 1 100.00
# 2 2 100.00
with_client( Client.find(1) ) do
Invoices.all # finds only invoice 1
Invoices.find(2) # finds nothing or raises
end
How can I do this with ActiveRecord, or at what points could I surgically alter AR to affect this behavior ?
Extra points: Id like to prevent the updating of this client_id column - it should be fixed at create-time
class Client < ActiveRecord::Base
has_one :invoice, :dependent => :destroy
end
class Invoice < ActiveRecord::Base
belongs_to :client
end
In controller
#client= Client.find(1)
#client.invoice #finds id =1 client_id =1 amount=100.0
There is a presentation here that discusses multi-tenanted applications. It has some interesting ideas to utilise database schemas, particularly for postgres.

Resources