ActAsTaggableOn in mongodb and rails 3 - ruby-on-rails-3

I want to adding tagging facility in my application . so, I am using acts_as_taggable_on : https://github.com/mbleigh/acts-as-taggable-on
I have added following line my Gemfile:
gem 'acts-as-taggable-on', '~> 2.2.2'
and when I add following line in my user model:
acts_as_taggable_on
It gives me this error:
undefined local variable or method `acts_as_taggable_on' for User:Class
Kindly, tell me what am I doing wrong?

That gem isn't going to work with mongoid and mongodb because it is built to allow tagging using a relational database using active record.
The good news is that this is very simple to do in mongoid. Simply add a new Array field named after whatever you would have listed as being acts_as_taggable_on. If you also have acts_as_taggable, include a generic tags field as well.
If you were going to have a model that looked like this:
class User < ActiveRecord::Base
acts_as_taggable
acts_as_taggable_on :skills, :interests
end
You would build it like this with mongoid:
class User
include Mongoid::Document
field :tags, type: Array
field :skills, type: Array
field :interests, type: Array
end
Then when you wanted to save a tag, lets say as an interest you would do the following:
#user.interests << 'computers'

Related

Activeadmin and Formtastic with HStore column

I am unable to edit or add a new model in activeadmin that has an HStore column due to the following error.
Unable to find input class for hstore
How can I get activeadmin and formtastic to play nice with my HStore column? This question has been asked but I cannot find a definitive answer that allows for adding and editing of the hstore field.
I have used these references so far
With latest activeadmin (which uses ransack instead of meta_search) it's possible to define a custom ransacker for hstore field in a model:
class Room < ActiveRecord::Base
store_accessor :options, :amenities
ransacker :amenities do |parent|
Arel::Nodes::InfixOperation.new('->', parent.table[:options], 'amenities')
end
end
Then it can be used in activeadmin for filtering:
ActiveAdmin.register Room do
filter :amenities_eq, label: 'Amenities', as: :select # ...
end
Filter activeadmin with hstore
and
https://github.com/gregbell/active_admin/issues/2032
For anyone who happens to stumble across this, I was able to use the activeadmin_hstore_editor gem for this purpose, which gives a way to input arbitrary json into an input field.

Retrieving sublist 3 level deep in Rails

I have a datamodel that contains a Project, which contains a list of Suggestions, and each Suggestion is created by a User. Is there a way that I can create a list of all distinct Users that made Suggestions within a Project?
I'm using Mongoid 3. I was thinking something like this, but it doesn't work:
#project = Project.find(params[:id])
#users = Array.new
#users.push(#project.suggestions.user) <-- this doesn't work
Any ideas? Here's my model structure:
class Project
include Mongoid::Document
has_many :suggestions, :dependent => :destroy
...
end
class Suggestion
include Mongoid::Document
belongs_to :author, class_name: "User", :inverse_of => :suggestions
belongs_to :project
...
end
class User
include Mongoid::Document
has_many :suggestions, :inverse_of => :author
...
end
While Mongoid can give MongoDB the semblance of relationships, and MongoDB can hold foreign key fields, there's no underlying support for these relationships. Here are a few options that might help you get the solution you were looking for:
Option 1: Denormalize the data relevant to your patterns of access
In other words, duplicate some of the data to help you make your frequent types of queries efficient. You could do this in one of a few ways.
One way would be to add a new array field to User perhaps called suggested_project_ids. You could alternatively add a new array field to Project called suggesting_user_ids. In either case, you would have to make sure you update this array of ObjectIds whenever a Suggestion is made. MongoDB makes this easier with $addToSet. Querying from Mongoid then looks something like this:
User.where(suggested_project_ids: some_project_id)
Option 2: Denormalize the data (similar to Option 1), but let Mongoid manage the relationships
class Project
has_and_belongs_to_many :suggesting_users, class_name: "User", inverse_of: :suggested_projects
end
class User
has_and_belongs_to_many :suggested_projects, class_name: "Project", inverse_of: :suggesting_users
end
From here, you would still need to manage the addition of suggesting users to the projects when new suggestions are made, but you can do so with the objects themselves. Mongoid will handle the set logic under the hood. Afterwards, finding the unique set of users making suggestions on projects looks like this:
some_project.suggesting_users
Option 3: Perform two queries to get your result
Depending on the number of users that make suggestions on each project, you might be able to get away without performing any denormalization, but instead just make two queries.
First, get the list of user ids that made suggestions on a project.
author_ids = some_project.suggestions.map(&:author_id)
users = User.find(author_ids)
In your Project class add this :
has_many :users, :through => :suggestions
You'll then be able to do :
#users.push(#project.users)
More info on :through here :
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_many
For mongoid, take a look at this answer :
How to implement has_many :through relationships with Mongoid and mongodb?

Issue with pushing additional values in a embeds_many mongoid relation

I have been breaking my head around this for a long time now. Not sure if my approach is correct or if its not possible using mongoid. SO without further adieu, here is the problem:
I have the following 2 models:
def user
embeds_many :needs, :class_name => "Property"
embeds_many :skills, :class_name => "Property"
end
def property
end
Both these models of course have other code but I have skipped that for brevity.
With this structure I am able to access/add "Property" data as embedded "needs" & "skills" on my user model. Something like this works flawlessly
User.first.update_attributes(skills: [Property.first])
The problem is something like this doesn't work.
User.first.skills.push(Property.first)
User.first.skills << Property.first
There is no error. Both the above statements return true on console. But the values don't persist to the DB.
I basically want a Property model which can be maintained/created independent of the User model, thats why the "embedded_in" on Property is missing in my code.
The question is, am I doing it right? Or there is their a different way that I should go about the design of these models?
Cage is right. You will need to put the embedded_in on the Property model if you want the persistence to work properly. If you want to manage the lifecycle of Property outside the User model, you will have to use 'has_many'.
Please add more details as to what exactly is the purpose of doing what you are doing. I am going to make some assumptions-
Needs and skills are a global list of values, that should be maintained separately
User can have a subset of skills and needs
You want to store the needs and skills as 'plain string' and not references so you can query them without referencing the needs and skills collection. This reduces one query
If the above is correct, then you can use custom keys to store the needs and skills-
class Property
include Mongoid::Document
field :text, :type => String
field :_id, type: String, default ->{ text }
end
class User
include Mongoid::Document
has_many :needs, :class_name => "Property"
has_many :skills, :class_name => "Property"
end
Now you can do something like-
User.first.need_ids
This will give the text of the need and you can avoid another query.
Note- that this is potentially very risky if your 'Property' objects are mutable.
For solution try doing this
u = User.first
u.skills.push(Property.first)
u.skills << Property.first
it will work fine.

how to make has_and_belongs_to_many relationship work in mongoid

i have the following code in the rails company model:
class Company
include Mongoid::Document
include Mongoid::Timestamps
field :name, type: String
...
has_and_belongs_to_many :users
end
User model:
class User
include Mongoid::Document
include Mongoid::Timestamps
include ActiveModel::SecurePassword
field :email, type: String
...
has_and_belongs_to_many :companies
end
There is a company record in the database, and a user record and they are associated. For some reason, the following code does NOT work:
c = Company.first
c.users # returns empty array
similarly, the followign code does not work:
u = User.first
u.companies
But the following code DOES work:
c = Company.first
user = User.find c.user_ids.first
and the following code also works:
u = User.first
company = Company.find u.company_ids.first
so if i try to access users from the company.users, it does not work, but the user_ids array does have a list of user ids, and when i try to access the users from this list, it works. How can i fix this issue?
i am using rails 3.2.5 and mongoid 3.0.0.rc
I had exactly the same issue ;)
Make sure you're using mongodb version > 2.0.0, for more details see: http://mongoid.org/en/mongoid/docs/installation.html#installation

rails 3 pagination with kaminari on mongoid embedded documents

When I call paginate with kaminari on a collection of embedded documents I get the following error:
(Access to the collection for Document is not allowed since it is an embedded document, please access a collection from the root document.):
Any idea on how I can fix that ? I have installed kaminari as a gem.
Alex
You just need to access the collection through the parent object. For example, given the following models:
class User
include Mongoid::Document
embeds_many :bookmarks
end
class Bookmark
include Mongoid::Document
embedded_in :user
end
Then to paginate a given user's bookmarks you would do:
#user.bookmarks.page(params[:page])
I found this issue on Kaminari: https://github.com/amatsuda/kaminari/issues/89
So I forked it, and fixed it following the solution provided by spatrik. I am not 100% sure it will work on all cases and that this solution does not have any drawbacks. But for the moment it works exactly as expected.
Alex
I just sent a patch for the issue. Take a look at the request. hope this helps solve your issue.
https://github.com/amatsuda/kaminari/pull/155/files
With the previous theTRON example :
class User
include Mongoid::Document
embeds_many :bookmarks
end
class Bookmark
include Mongoid::Document
field :created_at, :type => DateTime
embedded_in :user
end
the following, will get you the error you described in your post :
#user.bookmarks.desc(:created_at).page(params[:page])
while the nex one will works fine :
#user.bookmarks.page(params[:page]).desc(:created_at)
I hope it help.