I am trying to test an associated document for a subscription service. Each subscription is embedded in an account and references a plan. Below is the various bits of code:
The account:
Factory.define :account, :class => Account do |a|
a.subdomain 'test'
a.agents { [ Factory.build(:user) ] }
a.subscription { Factory.build(:free_subscription) }
end
The subscription:
Factory.define :free_subscription, :class => Subscription do |s|
s.started_at Time.now
s.plan { Factory.build(:free_plan) }
end
The plan:
Factory.define :free_plan, :class => Plan do |p|
p.plan_name 'Free'
p.cost 0
end
The error:
Mongoid::Errors::InvalidCollection: Access to the collection for Subscription is not allowed since it is an embedded document, please access a collection from the root document.
If I comment out the line that links the plan to the subscription then the tests work, but obviously I can't test that the subscription has a plan.
Any suggestions would be greatly appreciated.
UPDATE:
Here are the models:
class Account
include Mongoid::Document
field :company_name, :type => String
field :subdomain, :type => String
field :joined_at, :type => DateTime
embeds_one :subscription
accepts_nested_attributes_for :subscription
before_create :set_joined_at_date
private
def set_joined_at_date
self.joined_at = Time.now
end
end
class Subscription
include Mongoid::Document
field :coupon_verified, :type => Boolean
field :started_at, :type => DateTime
referenced_in :plan
embedded_in :account, :inverse_of => :subscription
end
class Plan
include Mongoid::Document
field :plan_name, :type => String
field :cost, :type => Integer
field :active_ticket_limit, :type => Integer
field :agent_limit, :type => Integer
field :company_limit, :type => Integer
field :client_limit, :type => Integer
field :sla_support, :type => Boolean
field :report_support, :type => Boolean
references_many :subscriptions
end
You need to create an account with the subscription for it to be valid.
Factory.define :free_subscription, :class => Subscription do |s|
s.started_at Time.now
s.plan { Factory.build(:free_plan) }
s.account { Factory(:account) }
end
Related
class Order
include Mongoid::Document
include Mongoid::Timestamps
#relationships
embeds_one :user_detail
#fields
field :description
#validations
validates :user_detail, presence: true
end
This the embedded object in order:
class UserDetail
include Mongoid::Document
include Mongoid::Timestamps
#fields
field :name, :type => String
field :zip_code, :type => String
field :email, :type => String
# Relationships
embedded_in :order
#validations
validates_presence_of :name, :zip_code, :email
end
I want save/persist on mongodb order object with user_detail object embedded_in order object.
I have tried with:
order = Order.new(description: "checking description")
order.user_detail = Order.new(:name => "John", :zip_code => "26545", :email => "john#john.com")
order.save!
but I get validation fail:
o.save!
Mongoid::Errors::Validations:
Problem:
Validation of Order failed.
Summary:
The following errors were found: User detail is invalid
Resolution:
Try persisting the document with valid data or remove the validations....
How can I fix this problem? I'm using mongoid 3.x
Should be:
order = Order.new(description: "checking description")
order.user_detail = UserDetail.new(:name => "John", :zip_code => "26545", :email => "john#john.com")
order.save!
You had Order.new for OrderDetail.new
You do not need to manually create user_detail using
order.user_detail = UserDetail.new...
order.save!
The embedded user_detail will be created automatically if u add autobuild attribute
embeds_one :user_detail autobuild: true
If u wanna persist user_detail in database as well, do not forget to add
validates_presence_of :user_detail
or you will not see the persisted user_detail in mongo db.
In reference to the Query DSL Explained Tutorial Slides 14-15
How do I flatten Nested Objects?
I have a Model named Entry and another named Category and they share a HABTM association.
Everything is currently working and the search results seem to be correct, but I don't know if my mapping is correct. The tutorial says that when you flatten objects the Document will look like this :
{
tweet => "Perl is GREAT!",
posted => "2011-08-15",
user.name => "Clinton Gormley",
user.email => "drtech#cpan.org",
tags => ["perl","opinion"],
posts => 2,
}
with the Object user being flattened. When I look at the source of my JSON document it looks like this:
{
"title":"First",
"description":"first test",
"categories":
{"categories_name":"CAP and Using the CAP website"},
"attachment":"VEVTVCE=\n",
"published":true
}
So, I'm assuming that its supposed to say categories.categories_name but I don't know how to specify that or if that's even necessary. Here's some Model code:
class Entry < ActiveRecord::Base
include Tire::Model::Search
include Tire::Model::Callbacks
has_and_belongs_to_many :categories
mount_uploader :doc, EntryDocUploader
tire.mapping do
indexes :title
indexes :description
indexes :categories do
indexes :categories_name, type: 'string', index: 'not_analyzed'
end
indexes :attachment, :type => 'attachment',
:fields => {
:title => { :store => 'yes' },
:attachment => { :term_vector => 'with_positions_offsets', :store => 'yes' }
}
end
def to_indexed_json
{
:title => title,
:description => description,
:categories => {:categories_name => cats}, #categories.map { |c| { :categories_name => c.name}}.to_sentence,
:attachment => attachment,
}.to_json
end
def self.search(params)
tire.search(load: true) do
query { string params[:query], default_operator: "AND" } if params[:query].present?
filter :term, :published => "true"
end
end
def cats
categories.map(&:name).to_sentence
end
end
Having a tough time wrapping my head around Tire's syntax, that of Elasticsearch and how they map together.
I have successfully indexed PDFs in a Rails app via Tire. But I need to break the full reports down into individual pages so queries can be more granular. It's easy enough to split the PDFs into individual pages and add them to a Page model that belongs_to the full Report model. What I'm struggling with is how to set up the mapping and where?!? I'd like to take advantage of Elasticsearch's Parent Field mapping so I can realize this ultimate goal.
Hoping someone can set me straight.
Report model (this is working for me if I index an entire PDF as the :attachment):
class Report < ActiveRecord::Base
include Tire::Model::Search
include Tire::Model::Callbacks
has_many :pages, :dependent => :destroy
attr_accessible :filename, :title
tire.mapping do
indexes :id, :type =>'integer'
indexes :title
indexes :attachment, :type => 'attachment',
:fields => {
:content_type => { :store => 'yes' },
:author => { :store => 'yes' },
:title => { :store => 'yes' },
:attachment => { :term_vector => 'with_positions_offsets', :store => 'yes' },
:date => { :store => 'yes' }
}
end
...
end
Page model:
class Page < ActiveRecord::Base
include Tire::Model::Search
include Tire::Model::Callbacks
belongs_to :report
attr_accessible :filename, :page_num,
tire.mapping do
indexes :id, :type => 'integer'
indexes :page_num, :type => 'integer'
indexes :report_id, :type => 'integer' ###<== how is this associated with _parent?
indexes :attachment, :type => 'attachment',
:fields => {
...
...
end
end
I have at least 2 classes. One class must validate one of its attributes based on the value of an associated model's attributes. The below code is what I am going for, but its just an idea, it doesn't work. Any way to achieve it?
class Concert
include Mongoid::Document
include Mongoid::Timestamps
field :end_date, type: Date
end
class Sale
include Mongoid::Document
field :end_date, type: Date
belongs_to :concert
validates :end_date, :timeliness => {
:before => lambda {self.concert.end_date},
:after => lambda {self.concert.created_at},
:before_message => 'Sale should not end before the Concert begins',
:after_message => 'Sale should not end after the Concert has already ended',
:type => :date
}
end
just a guess, but isn't there a problem with your reference to self in your lambdas? I'd go for => lambda { |record| record.concert.end_date }
add validation to Sale
validates :end_date, :presence => true, :if => :some_checking
def some_checking
#your validations
#eg
self.concert.end_date.present?
end
I have a profile model and it embeds_one kids_type and parent_type. As you can see in below code.
I want to validate kids_type child model. After using validates_associated, it's working fine for me.But problem is that, it validates kids_type model [#, #messages=**{:kids_type=>["is invalid"]}>**] , instead i am expecting field wise error, As i need to display inline error...
class Profile
include Mongoid::Document
validates_associated :kids_type
# PROFILE TYPE KIDS & PARENT
embeds_one :kids_type, :class_name => "ProfileKidsType"
embeds_one :parent_type, :class_name => "ProfileParentType"
end
class ProfileType
include Mongoid::Document
#COMMON FILES FOR KIDS AND PARENT
field :fname, :type => String
field :lname, :type => String
validates_presence_of :fname, :message => "ERROR: First name is required"
validates_presence_of :lname, :message => "ERROR: Last name is required"
end
class ProfileParentType < ProfileType
include Mongoid::Document
field :email, :type => String
embedded_in :profile, :inverse_of => :parent_type
end
class ProfileKidsType < ProfileType
include Mongoid::Document
field :nickname, :type => String
embedded_in :profile, :inverse_of => :kids_type
end
Any suggestion would be appreciated, Thanks in advance.
Try this here #profile is instance of Profile, it will give you all errors field wise for kids type
#profile.kids_type.errors