I am using Rails 3 with Mongoid.
I have two documents:
class MyUser
include Mongoid::Document
field ......
references_many :statuses, :class_name => "MyStatus"
end
class MyStatus
include Mongoid::Document
field ......
referenced_in :user, :class_name => "MyUser"
end
The problem is, I can get the user of any given status, but I cannot get the list of statuses from a user!
ie.
status = MyStatus.first
status.user # the output is correct here
user = MyUser.first
user.statuses # this one outputs [] instead of the list of statuses...
Please tell me what have I done wrong? I am just a few days with mongo......
Your code looks correct to me.
Are you sure that MyStatus.first.user == MyUser.first ?
It's possible that you have multiple users in your db.. where the first user has no statuses, and the second user has status1 in his list.
To test this, try doing:
status = MyStatus.first
user = status.user
user.statuses # Should return at least one status
Related
I need an activerecord query to Match ALL items in a params array.
Lets say user has_many roles. and each role has a name.
when i pass ['actor', 'producer', 'singer']. I expect the query to return me the users with all the those three roles or more.
But my method implementation below would return users with having atleast one role name matching to those in the array passed
My current method gives results based on finding any of the tags, not "MATCH ALL"
class User < ActiveRecord::Base
has_many :roles
def self.filter_by_roles(roles)
User.joins(:roles).includes(:roles).where(:roles => {:name => roles})
end
end
I don't want to do any array operations after the query checking if the returned result objects contain all the roles or not. This is because I need the Active Record Relation object to be returned from this.
Thanks in advance.
Try this.
User.joins(:roles).includes(:roles).where(:roles => {:name => roles}).group('usermail').having("COUNT(DISTINCt role_id) = 3")
assuming that field usermail is using to identify users.
You could try this:
def self.filter_by_roles(roles)
scope = User.joins(:roles).includes(:roles)
roles.each do |role|
scope = scope.where(roles: {name: role})
end
scope
end
It's untested, so I'm not sure whether it works.
If you pass role_ids array ([1,2,3]) you can do smth like this:
def self.filter_by_roles(role_ids)
User.select{|user| (role_ids - user.role_ids).empty?}
end
But if you pass roles by title (['actor', 'producer', 'singer']) you need smth like this:
def self.filter_by_roles(roles)
role_ids = Role.find_all_by_title(roles).map(&:id)
User.select{|user| (role_ids - user.role_ids).empty?}
end
i have the following code in the rails company model:
class Company
include Mongoid::Document
include Mongoid::Timestamps
field :name, type: String
...
has_and_belongs_to_many :users
end
User model:
class User
include Mongoid::Document
include Mongoid::Timestamps
include ActiveModel::SecurePassword
field :email, type: String
...
has_and_belongs_to_many :companies
end
There is a company record in the database, and a user record and they are associated. For some reason, the following code does NOT work:
c = Company.first
c.users # returns empty array
similarly, the followign code does not work:
u = User.first
u.companies
But the following code DOES work:
c = Company.first
user = User.find c.user_ids.first
and the following code also works:
u = User.first
company = Company.find u.company_ids.first
so if i try to access users from the company.users, it does not work, but the user_ids array does have a list of user ids, and when i try to access the users from this list, it works. How can i fix this issue?
i am using rails 3.2.5 and mongoid 3.0.0.rc
I had exactly the same issue ;)
Make sure you're using mongodb version > 2.0.0, for more details see: http://mongoid.org/en/mongoid/docs/installation.html#installation
I have 2 models TourHdr and TourDetail. TourDetail belongs_to tour_hdr and TourHdr has_many tour_details. TourHdr also has an attribute called status.
I want to define a method in TourDetail which will give me all TourDetails where the status field in the associated TourHdr record = Live.
I tried the following:
def self.status(status)
where(:tour_hdr.status == status)
end
status here can be 'Live' or 'Cancelled'.
Rails complains that there is no tour_hdr method for Class TourDetail. What is the correct syntax here?
In the console if I do:
td = TourDetail.first
puts td.tour_hdr.status
It works fine. I'm guessing it's because td is an 'Instance' of TourDetail rather than the class.
joins(:tour_hdr).where(:tour_hdrs => {:status => status})
I'm using the permanent_records gem in my rails 3.0.10 app, to prevent hard deletes and it seems rails is ignoring my default scope in checking uniqueness
# user.rb
class User < AR::Base
default_scope where(:deleted_at => nil)
validates_uniqueness_of :email # done by devise
end
in my rails console trying to find a user by email that has been deleted results in null, but when signing up for a new account with a deleted email address results in a validation error on the email field.
This is also the case for another model in my app
# group.rb
class Group < AR::Base
default_scope where(:deleted_at => nil)
validates_uniqueness_of :class_name
end
and that is the same case as before, deleting a group then trying to find it by class name results in nil, however when I try to create a group with a known deleted class name it fails validation.
Does anyone know if I am doing something wrong or should I just write custom validators for this behavior?
Try scoping the uniqueness check with deleted_at
validates_uniqueness_of : email, :scope => :deleted_at
This can allow two records with the same email value as long as deleted_at field is different for both. As long as deleted at is populated with the correct timestamp, which I guess permanent_records gem does, this should work.
In my User model, I want to search for whether a user has multiple accounts (aka 'multis').
Users have sessions; sessions are customized to set
creator_id = ID of first user the session was logged in as, and
updater_id = ID of last user the session was logged in as
(Both columns are indexed.)
If I detect that the two are different when a session is saved, I save the session for posterity (and this query), because it means that the user logged in as one and then logged in as the other - aka they're a multi. (To catch the recursive base case, the creator_id is then reset on the current session.)
Here's the code that does it:
class Session < ActiveRecord::SessionStore::Session
attr_accessor :skip_setters
before_save :set_ip
before_save :set_user
def set_user
return true if self.skip_setters
# First user on this session
self.creator_id ||= self.data[:user_id]
# Last user on this session
self.updater_id = self.data[:user_id] if self.data[:user_id]
if self.creator_id and self.updater_id and
self.creator_id != self.updater_id
logger.error "MULTI LOGIN: User #{self.creator.login} and \
#{self.updater.login} from #{self.ip}"
# Save a copy for later inspection
backup = Session.new {|dup_session|
dup_session.attributes = self.attributes
# overwrite the session_id so we don't conflict with the
# current one & it can't be used to log in
dup_session.session_id = ActiveSupport::SecureRandom.hex(16)
dup_session.skip_setters = true
}
backup.save
# Set this session to be single user again.
# Updater is what the user looks for;
# creator is the one that's there to trigger this.
self.creator_id = self.updater_id
end
end
# etc... e.g. log IP
end
The following query does work.
However, it's ugly, not very efficient, and doesn't play well with Rails' association methods. Keep in mind that sessions is an extremely large and heavily used table, and users almost as much.
I'd like to change this into a has_many association (so that all the associational magic works); possibly :through => a :multi_sessions association. It should capture both directions of multihood, not just one like the current association.
How can this be improved?
class User < ActiveRecord::Base
has_many :sessions, :foreign_key => 'updater_id'
# This association is only unidirectional; it won't catch the reverse case
# (i.e. someone logged in first as this user and then as the other)
has_many :multi_sessions, :foreign_key => 'updater_id',
:conditions => 'sessions.updater_id != sessions.creator_id',
:class_name => 'Session'
has_many :multi_users, :through => :multi_sessions,
:source => 'creator', :class_name => 'User'
...
# This does catch both, but is pretty ugly :(
def multis
# Version 1
User.find_by_sql "SELECT DISTINCT users.* FROM users \
INNER JOIN sessions \
ON (sessions.updater_id = #{self.id} XOR sessions.creator_id = {self.id}) AND \
(sessions.updater_id = users.id XOR sessions.creator_id = users.id) \
WHERE users.id != #{self.id}"
# Version 2
User.find(sessions.find(:all, :conditions => 'creator_id != updater_id',
:select => 'DISTINCT creator_id, updater_id').map{|x|
[x.creator_id, x.updater_id]}.flatten.uniq - [self.id])
end
end
I think the problem you're trying to solve of session re-use is a strange one. You're much better off mapping IPs to unique logins by processing your logs to detect sock-puppets or users with multiple accounts. There are more reliable and easier ways to solve your problem.