Mongoid and Full_text search issue - ruby-on-rails-3.1

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.

Related

Store gem configuration in the gem's module

My gem exposes a module that can be included on Mongoid mapper classes to keep track of changes.
I want the user to be able to flag specific fields on their classes so that they will be handled differrently.
My idea is to create an appendable flag. Please see an outline of the relevant sections of the module below:
module PendingChanges
included do
attr_accessor :__appendable_fields
private def self.appendable(field)
self.__appendable_fields << field
end
end
end
So when the user want to flag a field on his document as "appendable" they would do something like:
class Person
include PendingChanges
field :name, type: String
field :emails, type: Array
appendable :emails <- this is what they would do
end
I don't seem to be able to make it work, as __appendable_fields is always nil. Also, I'm not confident this is the "Ruby way" of approaching this?
Apparently, I had to use mattr_accessor instead.
I'm able to access it then with self.__appendable_fields on the appendable method.

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.

Tire (an elasticsearch client) needs pagination to perform an import, how do I do this with a custom model?

If I have a simple class like:
class Article
include Tire::Model::Persistence
property :title, :analyzer => 'snowball'
property :published_on, :type => 'date'
property :tags, :default => [], :analyzer => 'keyword'
end
It seems that I can only perform Article.import if there is a pagination method. But because this is a custom persistent model and I'm not using ActiveRecord, I am not able to use WillPaginate or Kaminari. So is there a custom method I can create to support pagination, and if so what requirements must it meet?
Looking at import method (https://github.com/karmi/tire/blob/master/lib/tire/index.rb#L103-124) looks like there are two options.
Create a paginate method that gets per_page and page parameters in options hash.
Create a map enumerator that returns all documents.
Then looking at bulk_store https://github.com/karmi/tire/blob/master/lib/tire/index.rb#L67-79 you have meet some other requirements for the document itself. Look at methods https://github.com/karmi/tire/blob/master/lib/tire/index.rb#L67-79
I was using mongoid as well and I found that I needed to require 'will_paginate/array' within my environment .rb in order to pull in the records. I don't think you need to use it after that but will_paginate helps with the import process.

overriding password_digest validation in rails 3.1 has_secure_password

So I wish to allow empty password_digest in has_secure_password, but looking at ActiveModel::SecurePassword seems like it is hardcoded:
validates_presence_of :password_digest
Is the only way to override this is by using monkey patching?
I don't think has_secure_password will do what you want, as you discovered.
So instead of using has_secure_password, you could write your own, basically copy the source and 'fork' it to do what you want -- only generate and validate a password if #user is not nil, is what it sounds like you want.
Or, as jtomasri suggests, you could make an Employee model and a User model -- you can use the ActiveRecord 'single table inheritance' feature to have them still both be in the same table, and have a common super-class you can still fetch upon (say, Account.find to return both Employees and Users matching your criteria). In some ways this is the 'cleaner' solution, although it's increasing the complexity of the behind the scenes ActiveRecord stuff -- in the past single table inheritance was a bit buggy, I think they are behaving well these days. (Haven't used it myself in a while).
I just had an related issue and used the :if operator for the validation.
validates :password ,..., :if => :employee_needs_password?
validates :password_confirmation , ... , :if => :employee_needs_password?
def employee_needs_password?
# check whatever your condition is and return true/false
end
why would you include has_secure_password if you want an empty password or why would you implement password's if you accept empty ones. Anyways you can always implement your own digest method without using has_secure_password using BCrypt, there's a Railscast #250 Authentication from scratch where you can see this in action

How to get activerecord associations via reflection

For normal columns, you can get at them via the columns class method. However, associations may be named something quite different if the foreign_key option is set in the relationship method. For example, given
class Post
has_many :comments, :foreign_key => :message_id # this is a contrived example
end
if I did Post.column_names I could get at message_id, but is there any way to get comments?
Model.reflections gives information about a model's associations. It is a Hash keyed on the association name. e.g.
Post.reflections.keys # => ["comments"]
Here is an example of some of the information it can be used to access:
Post.reflections["comments"].table_name # => "comments"
Post.reflections["comments"].macro # => :has_many
Post.reflections["comments"].foreign_key # => "message_id"
Note: this answer has been updated to cover Rails 4.2 based on MCB's answer and the comments below. In earlier versions of Rails the reflection's foreign_key was accessed using primary_key_name instead, and the keys for the reflections may be symbols instead of strings depending on how the association was defined e.g. :comments instead of "comments".
For future Googlers in Rails 4 the answer would now be:
Post.reflections[:comments].foreign_key # => "message_id"
Taken from here: https://stackoverflow.com/a/15364743/2167965
EDIT:
reflections, as of 4.2, now takes strings instead of symbols which is a fun bug to track down. If you want to keep using symbols you should switch to reflect_on_association(:assoc_name). Also note reflections are actually the public api which will keep reporting things like HABTM, even though it's all has many through under the hood. The reflections Rails is actually using are now in _reflections
For an ActiveRecord object I use:
object._reflections
So, I can manipulate the Hash returned. For instance:
object._reflections.keys.each do |key|
object.public_send(key).destroy_all
end
The above example delete all the relationships from database.

Resources