I have a question regarding mongoid id storage for references_many.
Suppose I have the following classes:
class A
include Mongoid::Document
field :name
attr_accessible :name, :b_ids
references_many :bs, :stored_as :array, :inverse_of :a
end
class B
include Mongoid::Document
field :name
attr_accessible :name, :a_id
referenced_in :a
end
If I do the following:
a = A.create(:name => "a1")
b = B.create(:name => "b1")
b.a = a
Should I expect the a.b_ids array to be an array that contains b's id?
The behaviour I am seeing is that b.a_id contains a's id, but a.b_ids does not contain b's id.
Is the id array on A's side supposed to be manually updated?
BTW, if I do a.bs << b, then a.b_ids gets updated correctly.
To answer my own question, the id arrays are not automatically set at the moment.
This feature is planned to be included once the refactor branch of mongoid is released.
This info comes from this thread: http://groups.google.com/group/mongoid/browse_thread/thread/9ac74dc9a08a5fe2/d3a7c2404b67abfa
Until then, the ids have to be tracked manually.
An example would be:
class A
include Mongoid::Document
field :name
attr_accessible :name, :b_ids
references_many :bs, :stored_as :array, :inverse_of :a
def add_b b
bs << b
self.save
end
def remove_b b
b_ids.delete b.id
b.save
end
end
class B
include Mongoid::Document
field :name
attr_accessible :name, :a_id
referenced_in :a
end
a = A.create(:name => "a1")
b = B.create(:name => "b1")
b.a = a
a.add_b b
Related
I have a User model which embeds a Profile:
# app/models/user.rb
class User
embeds_one :profile
end
# app/models/profile.rb
class Profile
embedded_in :user, inverse_of: :profile
field :age, type: integer
end
Now I want to declare a scope in User which can list out all users whose profile.age is > 18.
You can query attributes of embedded documents via:
User.where(:'profile.age'.gt => 18)
or as a scope:
class User
embeds_one :profile
scope :adults, -> { where(:'profile.age'.gt => 18) }
end
When you use embeds you can access only associated B objects of A. So, your need i.e all B where age>x doesn't work. So, go for has_one and belongs_to
A.rb
class A
has_one :b
scope :adults, -> { Bar.adults }
end
B.rb
class B
field :age ,type:integer
belongs_to :a
scope :adults, -> { where(:age.gt=> 18)}
end
This should save your day -))
Class B
field :age, type:integer
scope :adults, -> { where(:age.gt => 18) }
end
class A
embed_one :b
def embed_adults
b.adults
end
end
https://mongoid.github.io/old/en/mongoid/docs/querying.html#scoping
I have two models Item and Tag
class Item
include Mongoid::Document
field :title, type: String
has_many :tags
validates_length_of :tags, minimum: 1
end
class Tag
include Mongoid::Document
field :title, type: String
belongs_to :item
end
The Item must have minimum 1 tag.
When item is created validation works very well:
item = Item.create(title: "black hole")
item.tags << Tag.create(title: "black")
item.tags << Tag.create(title: "heavy")
puts item.valid? # => true
item.save
But validation fails when the existed item is modified:
item = Item.find(item.id)
item.title = "nothing"
puts item.tags.count # => 2, it's ok
puts item.valid? # => false, it's wrong
How to validate count of related documents properly?
Have you tried adding attr_accessible to title?
It would look like this:
class Item
include Mongoid::Document
attr_accessible :title # <-- here
field :title, type: String
has_many :tags
validates_length_of :tags, minimum: 1
end
I'm using single table inheritance in conjunction with a polymorphic association. Here are my models.
class ChangeInformation < ActiveRecord::Base
belongs_to :eventable, :polymorphic => true
end
class Race < ActiveRecord::Base
has_many :track_condition_changes, :as => :eventable, :class_name => "ChangeInformation"
#other associations omitted
end
class TrackConditionChange < ChangeInformation
end
The change_informations table has the following fields:
type #sti field
change_code
eventalbe_id #polymorphic id
eventable_type #polymorphic type
description
When I use the following create method:
TrackConditionChange.create(:change_code => 1, :eventable_id => 3 :description => "test")
a TrackConditionChange record is created, with the type field populated, however, the eventable_type field (which should be Race) is not populated. I was under the impression that rails populated this field automatically similar to the STI type field. Was I under the wrong impression or is there a problem with my associaition setup.
Thanks for the input.
If you're only passing in the eventable_id, how will it know what type it is? You will have to either pass the entire eventable object or build it based on the track_condition_changes relationship:
1. Pass the eventable object:
race = Race.find(3)
TrackConditionChange.create(:change_code => 1, :eventable => race, :description => "test")
2. Build and save based on the relationship:
race = Race.find(3)
race.track_condition_changes << TrackConditionChange.new(:change_code => 1, :description => "test")
I have the following validates_associated scenario
class Parent
include Mongoid::Document
validates_associated :son
validates_associated :daughter
end
when i create a parent, either of son or daughter is only created not both.
Now my problem is, when i try to create parent with son, then validation fails due to daughter validation and vice versa.
Is there any way that i can validate only son when son parameters are posted or or validate only daughter when daughter parameters are posted
Thanks
You can supply an :if option and test if the associated document exists:
class Parent
include Mongoid::Document
validates_associated :son, :if => Proc.new { |p| p.son.present? }
validates_associated :daughter, :if => Proc.new { |p| p.daughter.present? }
end
Why don't you use an associated child object, which has an attribute (i.e. gender) if it's beeing a son or a daughter.
Child model (male or female, depending on value in gender):
class Child
include Mongoid::Document
field :gender, :type => Symbol
# and more fields as you probably want
embedded_in :parent, :inverse_of => :child
# your validation code
def son?
gender == :male
end
def daughter?
gender == :female
end
end
will be Embedded in Parent model:
class Parent
include Mongoid::Document
embeds_one :child
validates_associated :child
end
I have 2 models A and B.
class A < ActiveRecord::Base
has_one :b
acts_as_ferret :fields => [:title,:description]
In a_cotroller, i wrote:
#search=A.find_with_ferret(params[:st][:text_search],:limit => :all).paginate :per_page =>10, :page=>params[:page]
The above title and description search is properly working.
class B < ActiveRecord::Base
belongs_to :a
Now,I want to perform a text search by using 3 fields; title, description(part of A) and comment(part of B). Where I want to include the comment field to perform the ferret search.Then,what other changes needed.
The documentation of find_with_ferret indicates that you simply code :store_class_name => :true to enable search over multiple models. While this is true there is a little more to it. To search multiple do the following:
#search = A.find_with_ferret(
params[:st][:text_search],
:limit => :all,
:multi => [B]
).paginate :per_page =>10, :page=>params[:page]
Notice the multi option. This is an array of the additional indexes to search.
Now to get his to work you have to rebuild your indexes after adding :store_class_name => :true to the index definitions.
class A < ActiveRecord::Base
has_one :b
acts_as_ferret :store_class_name => :true, :fields => [:title, :description]
end
OR...
You can simply include Bs fields in the index definition:
class A < ActiveRecord::Base
has_one :b
acts_as_ferret :fields => [:title, :description],
:additional_fields => [:b_content, :b_title]
def b_content
b.content
end
def b_title
b.title
end
end
This makes everything simple, but doesn't allow to search the B model independently of A.