Where can I find a specific documentation for a Mongoid class? - ruby

I am new to Mongoid and I want to learn more about it. Today I came across Mongoid::Timestamps in here .
It looks interesting to me so I wanted to know more about it, but could not find any more documentation on Mongoid::Timestamps. I've currently tried searching here, in Class List, Method List and File List, but didn't find anything.
Seems like Mongoid has a very limited documentation.

You can read its RubyDoc to find more about Mongoid::Timestamps. It's nothing special, but in a nutshell:
Including Mongoid::Timestamps in your Ruby model classes would tell MongoDB to save timestamps of when a document was created or updated. This creates two new attributes in your model:
created_at
updated_at
You use it like this:
class User
include Mongoid::Document
include Mongoid::Timestamps
# Other stuff...
end

Related

Can I remove an embedded document in Mongoid without persisting?

Definitely related to this question, but since there was no clear answer, I feel like I should ask again. Is there any way to remove an embedded document from a Mongoid embeds_many relationship, without persisting?
I want to modify the array of embedded documents in-memory - and then persist all changes with a single UPDATE operation. Specifically, I'd like to:
Modify arrays of embedded documents (add embedded doc / remove embedded doc / edit embedded doc / etc).
Possibly make other changes to the TLD.
Persist all changes with a single database call.
It is possible to remove an embedded document using Mongoid without saving. The trick is to make your changes from the parent object using assign_attributes. For exmaple:
class MyParent
include Mongoid::Document
field :name, type: String
embeds_many :my_children
def remove_my_child(child)
assign_attributes(my_children: my_children.select { |c| c != child })
end
end
class MyChild
include Mongoid::Document
embedded_in :my_parent
def remove
parent.remove_my_child(self)
end
end
my_parent = MyParent.first
my_first_child = my_parent.my_children.first
# no mongo queries are executed
my_first_child.remove
# now we can make another change with no query executed
my_parent.name = 'foo'
# and finally we can save the whole thing in one query which is the
# reason we used an embedded document in the first place, right?
my_parent.save!
After two more years of using Mongoid, I've learned there's no operator for what I was trying to achieve. Removing an embedded document with Mongoid always results in a database call.
In situations like this one, it's easier to bypass Mongoid and use the mongo-ruby-driver directly.
Try mongoid's
update_all()
Documentation
Ex: If I wanted to make all my users Joe
User.update_all(name: 'Joe')
will behave exactly as you would expect.

Update or Push Embedded Document to Array

I have two document
class Holder
include Mongoid::Document
embeds_many :things
end
class Thing
include Mongoid::Document
embedded_in :holder
end
Is there a way to find if some element exists in Holder.things and updated it or if not create a new one? Similar to the upsert flag in mongoDB.
Thank you.
What have you tried so far? Look into the embedded 1-N relationship functions that Mongoid provides (here).
#myHolder.things.find_or_create_by(attr: 'val')
# or
if #myHolder.things.where(attr: 'val').empty? ...

Understanding how ActiveRecord exists? works when building an association

I have two models that are associated via a has_many relationship. E.g.
class Newspaper < ActiveRecord::Base
has_many :articles
end
class Article < ActiveRecord::Base
belongs_to :newspaper
validates :uid, presence: true,
uniqueness: { case_sensitive: true }
end
A newspaper is updated several times a day but we only want to construct and add articles to the association that do not already exist. The following code was my first cut of achieving this.
new_articles.each do |article|
unless newspaper.articles.exists? uid: article.uid
newspaper.articles.build(uid: article.uid)
end
end
The newspaper object is either new and unsaved, or retrieved with existing relationships at this point.
My tests indicate that I am able to add two articles to the newspaper that have the same UID using the code above and this is obviously not want I want.
I appears to me that my current code will result in a validation failure upon being saved as the validation looks at uniqueness across the entire articles table and not the association.
What I'm struggling to understand is how the exists? method behaves in this scenario (and why it's not saving my bacon as I planned). I'm using FactoryGirl to build a newspaper, add an article and then simulate an update containing an article with the same uid as the article I've already added. If the code works I should get only one associated article but instead I get two. Using either build or create makes no difference, thus whether the article record is already present in the database does not appear to change the outcome.
Can anyone shed some light on how I can achieve the desired result or why the exists? method is not doing what I expect?
Thanks
The association exists? actually creates a scoped query, as per the association. This is why your existing articles filter doesn't work.
unless newspaper.articles.exists? uid: article.uid
# `articles.exists?` here will produce this if the newspaper is new
# ... WHERE "articles"."newspaper_id" IS NULL AND "articles.uid" = '<your uid>'
# and this, if the newspaper is persisted (with an id of 1)
# ... WHERE "articles"."newspaper_id" = 1 AND "articles.uid" = '<your uid>'
The case of the new newspaper is clearly wrong, as it would only return articles with a nil newspaper ID. But the persisted case is probably undesirable as well, as it still unnecessarily filters against newspaper ID, when you real concern here is that the UID is unique.
Rather, you probably want simply against Article, rather than scoping the exists? through the association, like:
unless Article.exists? uid: article.uid
Concerning your other problem:
this appears to be a FactoryGirl problem where the create method isn't creating db entries in the same way I can in the irb.
FactoryGirl.create should still abide by validations. It might help to see your test.

belongs_to a specific version

I need to store the specific version of a model with an order. I'm planning to use a versioning gem like paper_trail or vestal_versions. I'd like the correct version automatically loaded with the order.
Ideally, I'd simply store the object with order.update_attributes(:stuff => bought_stuff) and the order would remember the version of the stuff so that subsequent loads would make order.reload.stuff still be the object as it was when the order was saved.
Is there a gem that would provide such a functionality? I couldn't find one.
Otherwise, how can I achieve that with ActiveRecord and a versioning gem?
Actually, I could achieve almost what I want with PaperTrail and this :
class Stuff < ActiveRecord::Base
has_paper_trail
end
class Order < ActiveRecord::Base
belongs_to :stuff
def stuff_with_version
stuff_without_version.version_at(created_at) if stuff_without_version
end
alias_method_chain :stuff, :version
end
Not sure this is necessarily the best design for you, but you could use paper_trail for this. Simply add the macro method 'has_paper_trail' at the top of your model class and any time an instance changes, a serialised copy of it is created in a table called "versions" along with a polymorphic relationship back to the actual model.
Supposing you want to relate a particular version of a 'product' to an order, start by adding a relationship to the versions table - i.e. a migration that adds a 'version_id' to your order, and then set up the relationship as follows:
class Order
belongs_to :version
def product
version
end
def product=(p)
version=p.versions.last
end
end
class Product
has_paper_trail
end
Using this, when you add a product to an order, it will relate the order to the latest version of the product instead. When you retrieve the product, it will pull out the version; i.e. the product as it was when you created the order. Getting the relationship to work the other way around (i.e. relating products back to orders) might be more complicated, but this is a start.

Mongoid and Full_text search issue

I have been working on rails project, which had been made using noSql(Mongoid). Every thing is running fine.The issue is I want to add.. full text search here also. I had been using this gems for this...
gem 'mongoid_fulltext'
and my model file looks like this..
class Keyword
include Mongoid::Document
include Mongoid::FullTextSearch
field :name, type:String
#index :name, unique: true
embeds_many :posts
validates_presence_of :name
validates_uniqueness_of :name
fulltext_search_in :name, :index_name => 'name_index'
end
and in controller.
#keywords = Keyword.fulltext_search(params[:search], :index => 'name_index')
and then #keywords always returns an empty array always.
Thanks
Awieet
Apart from what I'm assuming are formatting errors, the only mistake I can find is that you seem to be naming the index manually.
Maybe in your fulltext_search call you should use :index_name => 'name_index' instead of :index => 'name_index'.
I'd advise just not messing with the default name of the index though, and removing that argument entirely from the method call.
Also, were the records persisted before you added the mongoid_fulltext gem? If so you'll need to call the update_ngram_index method on the Class object (or each instance) to add them to the index.
Other than that, have you checked out the mongoid_search gem as an alternative to mongoid_fulltext?
https://github.com/mauriciozaffari/mongoid_search
I've tried both and find find that this one has a much cleaner implementation and interface. Then again, I only use fulltext search sparingly. You may be using fulltext search more than I, and I'm not sure what the differences are feature-wise, but worth a look.
Hope that helps.

Resources