Embedded Document not being added - ruby-on-rails-3

Having trouble adding an embedded document. I am trying to add a tag which is embedded in the user.
user.rb
class User
include Mongoid::Document
field :name
validates_presence_of :name
validates_uniqueness_of :name, :email, :case_sensitive => false
attr_accessible :name, :email, :password, :password_confirmation
embeds_many :tags
embeds_many :tasks
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
tag.rb
class Tag
include Mongoid::Document
field :name
embedded_in :user, :inverse_of => :tags
references_many :tasks
end
tags_controller.rb
def create
##user = User.find(:first, :conditions => {:_id => "4d3ae09bf5c4930b2b000004"} )
#user = current_user
#tag = Tag.new(params[:tag])
#user.tags << #tag
#tag.save
redirect_to #tag, :notice => "Tag created!"
end
This is the output to the server when I try to create a new tag.
Started POST "/tags" for 127.0.0.1 at 2011-02-18 13:46:03 -0500
Processing by TagsController#create as HTML Parameters: {"utf8"=>"✓", "authenticity_token"=>"6p+Jova7Hol2v5LRReSp2fhNJ967EwkeIzAWyrChQRE=", "tag"=>{"name"=>"general"}, "commit"=>"Create Tag"}
db['users'].find({:_id=>BSON::ObjectId('4d39cd63f5c4930708000001')}, {}).limit(-1) MONGODB
db['users'].update({"_id"=>BSON::ObjectId('4d39cd63f5c4930708000001')}, {"$push"=>{"tags"=>{"name"=>"general", "_id"=>BSON::ObjectId('4d5ebe6bf5c493554d000002')}}}) Redirected to
http://localhost:3000/tags/4d5ebe6bf5c493554d000002 Completed 302 Found in 5ms
Not really sure what the issue is or where to start. It actually looks like the user is found then an update is being made to tags but it is not successful.
Thanks

The Tags class in your model is embedded inside of user (via the embeds_many association), rather than a table on its own. So following the updates in your controller, you should have something like this:
> db.users.find()
{
_id: ObjectId('4d39cd63f5c4930708000001'),
tags: [
{
_id: ObjectId('4d5ebe6bf5c493554d000002'),
name: "General"
}
]
}
Using MongoID, you can also have Tags appear in their own collection by replacing "embeds_many" with "references_many".
In the comments above, you'll see that the issue berek-bryan was having had to do with where the tag was being added. He expected the tag to be added in its own collection, hence the question. Actually, the tags were being added right into his users collection.

Related

Reserved word issue with ActiveAdmin rails 3.2

I have made the following addition to my active admin interface:
action_item :only => :show do
link_to('Approve this article', approve_admin_article_path(article)) if article.approved.nil?
end
member_action :approve, :method => :get do
# do approval
redirect_to :action => :show, :notice => "Approved!"
end
This throws the following error:
undefined method `approved' for
:Arbre::HTML::Article
What I think is happening is Active Admin thinks I'm passing an article tag in, not an article class?
Does anyone know of a work around for this? perhaps aliasing?
Thanks!
class Article < ActiveRecord::Base
attr_accessible :body
# Relations:
belongs_to :articleable, polymorphic: true, :counter_cache => true
has_many :comments, as: :commentable, order: 'created_at DESC', dependent: :destroy
# Validations
validates_presence_of :body
validates_length_of :body, maximum: 15000
end
Found a workaround
There is something fishy when you name your class as 'Article', ActiveAdmin relate to it when rendering as <article> HTML tag - The problem is somewhere in the controller of course because this is where the article object is being generated
So, I override the controller
ActiveAdmin.register Article do
controller do
def show
# grabbing my desired Article and not the <article> tag into some global variable
##myarticle = Article.find(params[:id])
end
end
sidebar :article_details , :only => :show do
ul do
# using the ##myarticle which I know should be initialized
# (you can put .nil? checking here if you want)
li link_to 'Article Images (' + ##myarticle.images.count.to_s + ')' , admin_article_article_images_path(##myarticle)
li link_to 'Article Clips ('+##myarticle.clips.count.to_s + ')' , admin_article_article_clips_path(##myarticle)
end
end
end
Enjoy
Assuming you're having the issue in the 'show' block, you could change the show block to the following:
show do |object|
end
Then you can call object.some_method without the clash. This way you don't need to override the controller.

Can't mass-assign protected attributes with has_many association and create

This is EXTREMELY bizarre. I'm upgrading a Rails 2.3.12 app and running into this same problem over and over again. I'm stumped and nothing else out there seems to touch on it.
I have two models:
class User < ActiveRecord::Base
has_many :logs, :class_name => 'UserLog'
end
and
class UserLog < ActiveRecord::Base
attr_accessor :site_id, :controller, :action, :url, :session
belongs_to :user
validates_presence_of :user
end
then in another controller I'm doing this:
def log_user_activity
#current_user.logs.create(:site_id => #site.id, :controller => params[:controller],
:action => params[:action], :url => request.path,
:session => request.session_options[:id]) if #current_user
end
as you can see, it's pretty straightforward but when I call log_user_activity I'm getting this:
Can't mass-assign protected attributes: site_id, controller, action, url, session
HOWEVER, if I change all my creates or builds to this:
def log_user_activity
log = #current_user.logs.new
log.site_id = #site.id
log.controller = params[:controller]
log.action = params[:action]
log.url = request.path
log.session = request.session_options[:id]
log.save
end
then it works fine!?
Has anyone seen this? Any clues?
In class UserLog, add the following:
attr_accessible :site_id, :controller, :action, :url, :session
The reason you have to use attr_accessible is most likely because you are utilizing a plugin that is relying on this being present for a model. It has happened to all of us and is a royal pita)
Once attr_accessible is designated for a class, then any attribute that is not specified as 'accessible' will not be allowed to be updated.

Rails 3 current user id to comments?

So Im working on a rails app where users can comment on photos or videos another user has uploaded and so far everything is great except I am not able to get the current user_id associated with the person who has commented on the post. This is what I have so far.
user.rb
has_many :comments, :dependent => :destroy
photo.rb
has_many :comments, :as => :commentable
video.rb
has_many :comments, :as => :commentable
comments_controller.rb
def create
#commentable = find_commentable
#comment = #commentable.comments.build(params[:comment])
if #comment.save
redirect_to :id => nil, :notice => "Successfully created comment."
else
render :action => 'new'
end
end
How can I get the user id to appear with the current comments? I have the comment type and comment id I am just looking for a way to have it so the user_id can appear. Any suggestions?
You should add a hidden_field to your form partial where you store the current_user.id
something like:
<%= f.hidden_field :user_id, :value => current_user.id %>
of course you should have a field user_id in your comment model, as a comment belongs_to user and a user has_many comments.
update:
what ofca pointed out, this can approach can lead to security issues as the hidden field could be modified by the user in the browser, e.g. using firebug.
In this case it is probably better to to leave out this field in the view and create the comment in the controller by using
<%= current_user.comments.create(params[:comment]) %>
The way you have it now, it is only set up one way.
Plus you have to make it polymorphic
try adding:
comment.rb
belongs_to :user
belongs_to :commentable, :polymorphic => true

MongoID, embedding a document in multiple documents

I have a model Address like following
class Address
include Mongoid::Document
field :line1
field :city
# more fields like this
embedded_in :user, :inverse_of => :permanent_address
embedded_in :user, :inverse_of => :current_address
embedded_in :college, :inverse_of => :address
end
There are models College and User which embed address
class College
include Mongoid::Document
references_many :users
embeds_one :address
# some fields and more code
end
class User
include Mongoid::Document
referenced_in :college, :inverse_of => :users
embeds_one :permanent_address, :class_name => "Address"
embeds_one :current_address, :class_name => "Address"
# fields and more code
end
I am getting some problems with the above setup. I am using single form to ask for current and permanent address along with some more information, but only current_address is getting saved and that too with the data I populate in permanent_address.
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"KdOLvzmKyX341SSTc1SoUG6QIP9NplbAwkQkcx8cgdk=",
"user"=> {
"personal_info_attributes"=>{...},
"nick_names_attributes"=>{...},
"current_address_attributes"=>{
"line1"=>"",
"area"=>"",
"country"=>"USA",
"postal_code"=>"sd",
"city"=>"",
"state"=>"",
"landmark"=>"",
"id"=>"4d891397932ecf36a4000064"
},
"permanent_address_attributes"=>{
"line1"=>"",
"area"=>"asd",
"country"=>"india",
"postal_code"=>"",
"city"=>"",
"state"=>"",
"landmark"=>""
},
"commit"=>"Submit", "id"=>"4d8903d6932ecf32cf000001"}
MONGODB alma_connect['users'].find({:_id=>BSON::ObjectId('4d8903d6932ecf32cf000001')})
MONGODB alma_connect['users'].update({"_id"=>BSON::ObjectId('4d8903d6932ecf32cf000001')},
{"$set"=>{
"current_address"=>{
"line1"=>"",
"area"=>"asd",
"country"=>"india",
"postal_code"=>"",
"city"=>"",
"state"=>"",
"landmark"=>"",
"_id"=>BSON::ObjectId('4d8916e9932ecf381f000005')}}})
I am not sure if this is something I am doing wrong here or there is some other problem. I am using Rails 3.0.4 and MongoID 2.0.0.rc.7
Update:
I upgraded to mongoid 2.0.1 and changed my user to include inverse of options in address.
class User
include Mongoid::Document
referenced_in :college, :inverse_of => :users
embeds_one :permanent_address, :class_name => "Address", :inverse_of => :permanent_address
embeds_one :current_address, :class_name => "Address", :inverse_of => :current_address
# fields and more code
end
I know the inverse of names doesn't make sense, but the main point here is just to make them different or if you have good names for relations in your embedded class(like :current_user, :permanent_user), you should use that for inverse of.
Looks good to me. I've a similar setup and it works as expected.

Trying to view a referenced document: illegal ObjectId format

Trying to view an attribute to a referenced document. The issue is in the task's index file. When I try to display the tag associated with the task I get the following error:
BSON::InvalidObjectId in Tasks#index
The error is on '<%= task.tag.title %>' line in the index.html.erb file.
user.rb
class User
include Mongoid::Document
field :name
validates_presence_of :name
validates_uniqueness_of :name, :email, :case_sensitive => false
attr_accessible :name, :email, :password, :password_confirmation
embeds_many :tags
embeds_many :tasks
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
tag.rb
class Tag
include Mongoid::Document
field :title
embedded_in :user, :inverse_of => :tags
references_many :tasks
end
task.rb
class Tag
include Mongoid::Document
field :title
embedded_in :user, :inverse_of => :tags
references_many :tasks
end
index.html.erb
<% #tasks.each do |task| %>
<tr>
<td><%= task.name %></td>
<td><%= task.tag.title %></td>
</tr>
<% end %>
Thanks,
I ran into a similar problem myself recently (2.0.0.rc.7). In my case a Rails collection_select was ending up writing an empty string value into a reference field (e.g. tag_id). When mongoid attempted to reload the document and my code referenced the association it failed to convert empty string to a valid BSON object ID.
It looks like it is a known issue and has been fixed but hasn't made it into a new build just yet.
https://github.com/mongoid/mongoid/issues/closed#issue/651
https://github.com/mongoid/mongoid/issues/closed#issue/690
In the meantime I ended up working around the problem by writing a before_save event handler to convert the empty string values to nil. e.g.
before_save :before_save
def before_save
self.tag_id = nil if self.tag_id == ''
end
Its just a workaround and should be unecessary with 2.0.0.rc.8. It will only stop invalid object references being saved, it won't clean up any data that is already in the database.