Rails model validation: two users cannot be the same - ruby

I have a model set out like so:
class Rating
# user_id, author_id
end
What I want to do is validate the author_id/user_id so they cannot be the same, essentially, so that a user cannot rate themselves.
Am I right to say this should be done using a validation in the Rating class?
validates :author_id, # custom validation options

You'll need a custom validation:
class Rating
# user_id, author_id
validate :ensure_author_is_not_user
private
def ensure_author_is_not_user
errors[:author_id] << "can not be the same as user" unless user_id != author_id
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.

How to retrieve object with relationship stored in string variable in rails 3.2.12 at run time?

Let's say there are models customer, account and address:
class Customer
has_many :accounts
end
class Account
belongs_to :customer
has_many :addresses
end
class Address
belongs_to :account
end
Given an object address, its customer could be retrieved as:
customer = address.account.customer
Now let's store the relationship in a string variable address_relation = 'account.customer'. Given an address object, is there a way to retrieve its customer with the string variable address_relation like:
customer = address.address_relation ?
thanks for the help.
I'd do something like
customer = address.address_relation.split(".").inject(address) do |object, method|
object.send(method)
end
You could switch send by try if there's a chance there is a nil object in your relation chain
Not sure I understand the problem correctly, but I guess you can use Ruby's send method to dynamically resolve the model relations.
object = customer
methods = "account.customer".split(".")
methods.each do |m|
object = object.send(m)
end

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.

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

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

How to Validate Rails 3 Relational Model?

New to Rails and ActiveRecord, not sure how I can apply validation though multiple levels of relational model. I've searched all the tutorials that I can find are all validation in just one model.
How can I validate multiple relational models ?
Say I have multiple models, one model called field stores different type of attribute in sports game.(ex. final score, goals for, goals against etc) and another model value that stores all the actual values like game scores into the field
So I will have 2 classes
class Field < ActiveRecord::Base
has_many :value
end
class Value < ActiveRecord::Base
belongs_to :field
end
How can I validate the value of each attributes in value model that are corresponding to it's field ?
In rails 3 : You can create a file in your lib directory (ensure that that this file is loaded by your application) and put in a class with a validate method :
class HumanValidator < ActiveModel::Validator
def validate(record)
record.errors[:base] << "This person is dead" unless check(human)
end
private
def check(record)
(record.age < 200) && (record.age > 0)
end
end
In all model you want to validate, you invoke the validation with the of the class like this:
# app/models/person.rb
class Customer < ActiveRecord::Base
validates_with HumanValidator
end
Go read this, for validate novelty in rails 3, soure link text

Resources