I have three models, Employee, Job, LeaveDay. like below:
class Employee
field :name
belongs_to :job
end
class Job
field :job_title
has_many :employees
has_many :leave_days
end
class LeaveDay
belongs_to :job
field :no_of_leave_days
end
I want to establish an relationship in which I want to track no_of_leave_days of employee related to their job. How is it possible. Thanks in advance.
i think u need to add 'belongs_to: employee' in LeaveDay and 'has_many: leave_days' in Employee. so, #emp.leave_days will get u all the leave for all the jobs of a particular employee. similarly, #emp.job.leave_days will return the leave_days for the current job of the cuttent employee.
I'm not really familiar with Mongoid. You may read here more about relations in mongoid.
It's very easy example. Hope it'll help.
This is models definition:
class Employee
include Mongoid::Document
field :name
belongs_to :job
end
class Job
include Mongoid::Document
field :job_title
has_many :employees
embeds_many :leave_days
end
class LeaveDay
include Mongoid::Document
embedded_in :job
field :no_of_leave_days
end
And example of usage:
pry(main)> j = Job.create(job_title: "Test Job")
=> #<Job _id: 510633e0784931179a000001, _type: nil, job_title: "Test Job">
pry(main)> LeaveDay.create(job: j, no_of_leave_days: 1)
=> #<LeaveDay _id: 5106348f784931179a000002, _type: nil, no_of_leave_days: 1>
pry(main)> LeaveDay.create(job: j, no_of_leave_days: 2)
=> #<LeaveDay _id: 51063687784931179a000003, _type: nil, no_of_leave_days: 2>
pry(main)> LeaveDay.create(job: j, no_of_leave_days: 3)
=> #<LeaveDay _id: 51063689784931179a000004, _type: nil, no_of_leave_days: 3>
pry(main)> Job.first.leave_days.map(&:no_of_leave_days)
=> [1, 2, 3]
pry(main)> Employee.create(name: 'Employee name', job: Job.first)
=> #<Employee _id: 510637cf784931179a000005, _type: nil, name: "Employee name", job_id: "510633e0784931179a000001">
pry(main)> Employee.first.job.leave_days.map(&:no_of_leave_days)
=> [1, 2, 3]
Related
class Hotel
include Mongoid::Document
field :title, type: String
embeds_many :comments
end
class Comment
include Mongoid::Document
field :text, type: String
belongs_to :hotel
validates :text, presence: true
end
h = Hotel.create('hotel')
=> <#Hotel _id: 52d68dd47361731d8b000000, title: "hotel">
c = Comment.new(text: 'text')
=> <#Comment _id: 52d68f3d7361731d8b040000, text: "text", hotel_id: nil>
h.comments << c
=> [#<Comment _id: 52d68f3d7361731d8b040000, text: "text", hotel_id: nil>]
h.save
=> true
Hotel.last.comments
=> []
variant 2
h.comments << Comment.new(text: 'new', hotel_id: h.id)
=> [<#Comment _id: 52d68f3d7361731d8b040000, text: "text", hotel_id: nil>, <#Comment _id: 52d691e17361731d8b050000, text: "new", hotel_id: BSON::ObjectId('52d68dd47361731d8b000000')>]
h.save
=> true
Hotel.last.comments
=> []
I see two possible problems:
Hotel.last is not necessarily Hotel 52d68dd47361731d8b000000. You should look at h.comments or to be paranoid, h.reload and h.comments.
Your associations are confused.
From the fine manual:
Embedded 1-n
One to many relationships where the children are embedded in the
parent document are defined using Mongoid's embeds_many and
embedded_in macros.
Defining
The parent document of the relation should use the embeds_many macro
to indicate it has n number of embedded children, where the document
that is embedded uses embedded_in.
So your relation should be defined like this:
class Hotel
embeds_many :comments
end
class Comment
embedded_in :hotel
end
You're using belongs_to: hotel in Comment when you should say embedded_in :hotel.
The docs also say that:
Definitions are required on both sides to the relation in order for it to work properly.
and your relation is incorrectly configured on one side so it won't work properly.
I am trying to select an instance based on a relation of that instance containing a set. A simplified example follows:
class Product::Variation < ActiveRecord::Base
attr_accessible :name, :product_id, :quantity
belongs_to :product
has_many :bids, :foreign_key => :product_variation_id
has_many :product_variation_property_values, :class_name => 'Product::Variation::PropertyValue'
has_many :property_values, :through => :product_variation_property_values, :class_name => 'Property::Value'
end
class Product::Variation::PropertyValue < ActiveRecord::Base
attr_accessible :property_value_id, :variation_id, :property_id
belongs_to :variation
belongs_to :property_value, :class_name => 'Property::Value'
end
class Property < ActiveRecord::Base
attr_accessible :name
has_many :values, :class_name => 'Property::Value'
end
class Property::Value < ActiveRecord::Base
attr_accessible :content
belongs_to :property
belongs_to :partner
end
So now I want to do something like the following (in psuedo code):
Variation.where(:property_values includes [Property::Value.find(1), Property::Value.find(2)])
Is there a way to do this using ActiveRecord?
Thanks and let me know if you need more info.
More Info
I tried the following:
Product::Variation.joins(:property_values).where('property_values.id' => [Property::Value.find(1).id, Property::Value.find(2).id]).first
...which is the following SQL...
SELECT "product_variations".* FROM "product_variations" INNER JOIN "product_variation_property_values" ON "product_variation_property_values"."variation_id" = "product_variations"."id" INNER JOIN "property_values" ON "property_values"."id" = "product_variation_property_values"."property_value_id" WHERE "property_values"."id" IN (1, 2)
...and this returns...
#<Product::Variation id: 25, product_id: 1, quantity: 39, created_at: "2013-11-18 00:18:45", updated_at: "2013-11-18 00:18:45">
But if I do:
Product::Variation.find(25).property_values.inspect
...I get...
[#<Property::Value id: 1, property_id: 1, content: "XS", created_at: "2013-11-18 00:18:45", updated_at: "2013-11-18 00:18:45", color: nil, color_texture: nil, secondary_color: nil>, #<Property::Value id: 6, property_id: 2, content: "Dark Wood", created_at: "2013-11-18 00:18:45", updated_at: "2013-11-18 00:18:45", color: "#855E42", color_texture: "striped", secondary_color: "#FFB90F">]
But I'm looking for the Product::Variation that contains both Property::Value 1 and 2. This is returning those that contain 1 or 2.
This should be doable with a join query. Hard to write form heart, but should be something like this:
Variation.joins(propert_values: :values).where('values.id' => [Property::Value.find(1).id, Property::Value.find(2).id]).first
I'm trying to achieve a really simple "multiple relationship" in Rails (3.2.12) with Mongoid (3.1.2). I got three models:
class User
include Mongoid::Document
field :name
has_many :collections
end
class Collection
include Mongoid::Document
field :name
belongs_to :user
has_many :things
end
class Thing
include Mongoid::Document
field :name
belongs_to :collection
end
So basically there is a user who has collections and there are collections which have "Things".
Well ... first question: Is this even possible? And if not: Why not? ;-)
I can create users now (from a rails console or via web), and I can create collections belonging to users. But when I try to create a "Thing" now ... well it just doesn't get created:
2.0.0-p0 :014 > u = User.first
=> #<User _id: 514b2b32e05658e1f1000005, name: "test">
2.0.0-p0 :015 > c = Collection.create!(name: "somename", user: u)
=> #<Collection _id: 514b30f0e05658ca67000001, name: "somename", user_id: "514b2b32e05658e1f1000005">
2.0.0-p0 :016 > t = Thing.create!(name: "a thing", collection: c)
=> #<Thing _id: 514b3120e05658ca67000002, name: "a thing", collection_id: "514b30f0e05658ca67000001">
2.0.0-p0 :017 > Thing.first
=> nil
The "Collection" gets created just fine:
2.0.0-p0 :018 > Collection.first
=> #<Collection _id: 514b2b65e05658e1f1000006, name: "test", user_id: "514b2b32e05658e1f1000005">
Change the Collection class name to something else, say to 'Stockpile'. MongoDB uses 'collection' as part of it's terminology, so it may not play well with your models.
Say I have two ActiveRecord Models (I'm not going to include migrations):
class User < ActiveRecord::Base
belongs_to :subscription, :inverse_of => :users
end
and
class Subscription < ActiveRecord::Base
has_many :users, :inverse_of => :subscription
end
In rails console I can create a new object for each model, then add a user to the subscription model:
>> s = Subscription.create
=> #<Subscription id: 1>
>> u = User.create
=> #<User id: 1, subscription_id: nil>
>> s.users << u
=> [#<User id: 1, subscription_id: 1>]
>> u
=> #<User id: 1, subscription_id: 1>
But if I use the Array.clear method, it clears out the collection, but doesn't immediately update the associated model:
>> s.users.clear
=> []
>> u
=> #<User id: 1, subscription_id: 1>
If I call u.reload it will pull the most recent version from the database, but it shouldn't have to do that in order to update my cached model. I tried using :inverse_of as suggested in Bi-Directional Associations, but it didn't work.
I've created two models with the below associations
class User < ActiveRecord::Base
has_many :roles, :dependent => :destroy
end
class Role < ActiveRecord::Base
belongs_to :user
end
class Student < Role
end
class Tutor < Role
end
However when I create a new child role, I assume it would get associated to the model it has the belongs to for.
Such as:
Tutor.create(:user_id => user_id)
I would expect:
#some user #user
#user.roles
to have an array containing a Tutor. However, it doesn't seem to be working. Any ideas what I'm doing wrong?
Once you start using Single Table Inheritance, than the Tutor that you created isn't a role, as far as active-record is concerned for this type of query.
class User < ActiveRecord::Base
has_many :roles
has_many :tutors
end
#user = User.first
#user.roles
=> []
#user.tutors
=> [#<Tutor id: 1, user_id: 1, type: "Tutor", created_at: "2012-10-26 18:15:16", updated_at: "2012-10-26 18:15:16">]
If you want to get a list of all roles that your users may have:
Role.where(user_id: #user.id).all
[#<Tutor id: 1, user_id: 1, type: "Tutor", created_at: "2012-10-26 18:15:16", updated_at: "2012-10-26 18:15:16">, #<Student id: 2, user_id: 1, type: "Student", created_at: "2012-10-26 18:18:32", updated_at: "2012-10-26 18:18:32">]