Trying to view a referenced document: illegal ObjectId format - ruby-on-rails-3

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.

Related

How to create new records with nested attributes in a ruby on rails "has many through" relationship?

I need some advice on building a has many through relationship between USER, THING and EXTRA models.
My USER model is slightly modified inside Devise gem and is noted as Creator whereas other models belonging to USER receive :created_things form.
In my app, USERS create THINGS can later add EXTRAS to their THINGS.
I chose has many through because I want to have unique data on all three models and be able to call both THINGS and EXTRAS from the USER "CREATOR" model.
I have built this many different ways and after 10 years of solving my problems by reading stackoverflow, I am finally submitting this request for support! Thank you for your help.
I have tried creating user and extra references on the THING model and declaring nested attributes in the USER and THING model. I have tried several examples from stackoverflow inside the create and new methods but nothing seems to work.
class User < ApplicationRecord
has_many :created_things, class_name: Thing, foreign_key:
:creator_id, :dependent => :destroy
has_many :extras, through: :created_things
accepts_nested_attributes_for :extras, :reject_if => :all_blank,
allow_destroy: true
class Thing < ApplicationRecord
belongs_to :creator, class_name: User
has_many :extras
accepts_nested_attributes_for :extras, :reject_if => :all_blank,
allow_destroy: true
class Extra < ApplicationRecord
belongs_to :creator, class_name: User, inverse_of: :thing
belongs_to :created_things
Members Index.html.erb
<% if thing.extras.exists? %>
<% thing.extras.each do |extra| %>
<%= extra.title %> <%= link_to "[+]", edit_extra_path(extra) %>
<% end %>
<% else if thing.extras.empty? %>
<%= link_to "+1 EXTRA", new_extra_path(current_user) %>
<% end %>
<% end %>
class MembersController < ApplicationController
before_action :authenticate_user!
def index
#user = current_user
#created_extras = #user.extras
#created_things = #user.created_things
end
class ExtrasController < ApplicationController
def new
#extra = Extra.new
end
def create
#extra = current_user.extras.build(extra_params)
if #extra.save
I am able to create a new EXTRA but the :thing_id remains nul as it does not display when called on the show extra view. Therefore I am not surprised that when I return to the member index page that my thing.extras.exists? call is returning false and the created extra never displays under the THING view. My attempts to modify the extra controller have failed and I some of my reading sugested the extras controller is not necessary in this relationship so I am really at a loss on how this is built. I'm assuming I am missing something in new and create methods maybe in things or user controller? Perhaps I'm missing something in routes resources? Any advice is greatly appreciated. Thank you.
Ok, I figured it out. I really didn't need has many through for this model and I did a lot of testing of the syntax on each model.rb and in the end was able to figure it out from this stackoverflow . . .
[Passing parent model's id to child's new and create action on rails
Here are my the various parts of setting up a has many and belongs to relationship with nested attributes.
class Thing < ApplicationRecord
belongs_to :creator, class_name: User
has_many :extras, inverse_of: :thing, :dependent => :destroy
accepts_nested_attributes_for :extras, allow_destroy: true
class Extra < ApplicationRecord
belongs_to :thing, inverse_of: :extras
extras_controller.rb
class ExtrasController < ApplicationController
def new
#extra = Extra.new(thing_id: params[:thing_id])
end
def create
#user = current_user
#extra = Extra.new(extra_params)
#extra.user_id = #user.id
if #extra.save
flash[:success] = "You have added a new Extra!"
redirect_to #extra #extras_path later
else
flash[:danger] = "The form contains errors"
render :new
end
end
edit.html.erb things
<% if #thing.extras.exists? %>
<p>current extras associated with <%= #thing.title %>: </p>
<% #thing.extras.each do |extra| %>
<p><%= extra.title %> <%= link_to "[+]", edit_extra_path(extra) %>
/ <%= link_to "[-]", extra_path(extra), method: :delete %> </p>
<% end %>
<% end %>
<%= link_to "+1 EXTRA", new_extra_path(thing_id: #thing.id) %>
<%= render 'things/form' %>

Rails 3 UnknownAttributeError For Nested Model

I've been getting the UnkownAttributeError for no particular reason, my models seem to be setup correctly...
School.rb
class School < ActiveRecord::Base
attr_protected :id, :created_at, :updated_at
#relationships
has_many :users
accepts_nested_attributes_for :users
end
My School model used to have the following, but it produced a MassAssignmentSecurity error for the user fields:
attr_accessible :country, :name, :state_or_province, :users_attributes
User.rb
class User < ActiveRecord::Base
attr_accessible :email, :password, :password_confirmation, :remember_me, :username, :instructor_id, :first_name, :last_name, :school_id
#relationships
belongs_to :school
end
new.html.haml
= simple_form_for #school do |f|
.well
= f.input :name, :as => :hidden
= f.input :country, :as => :hidden
= f.input :state_or_province, :as => :hidden
.well
= f.simple_fields_for #school.users.build do |user_form|
= user_form.input :first_name, :required => true
= user_form.input :last_name, :required => true
= user_form.input :username, :required => true
...
= f.button :submit, "Next"
Note: #school is being populated in my new action from session information gathered on the previous page, I'm making a multi-step form. The school data is perfectly valid, if I was to remove the user form it would have no trouble saving the school.
The specific error message I'm getting in my create action:
ActiveRecord::UnknownAttributeError in SchoolsController#create
unknown attribute: user
And the sent params looks a little like this:
{"school"=>{"name"=>"Elmwood Elementary", "country"=>"38",
"state_or_province"=>"448", "user"=>{"first_name"=>"joe",
"last_name"=>"asdas", "username"=>"asasdads",
"email"=>"asdasd#sdas.ca", "password"=>"[FILTERED]",
"password_confirmation"=>"[FILTERED]"}}, "commit"=>"Next"}
Is this maybe a bug with either Devise or simple_form? I'm using Rails 3.2.3
Ok, so apparently I needed to provide the symbol :users - the name of the relationship as my first argument for it to work.

Rails 3 polymorphic association with Carrierwave and Simple Form

I'm trying to set up a polymorphic association for photo uploads which are processed using Carrierwave. I'm using Simple Form to build my forms. I feel like the association is correct so I'm wondering if my problem is just something with the form or controller.
Here are my associations:
property.rb:
class Property < ActiveRecord::Base
attr_accessible :image
...
has_many :image, :as => :attachable
...
end
unit.rb
class Unit < ActiveRecord::Base
attr_accessible :image
...
has_many :image, :as => :attachable
end
image.rb
class Image < ActiveRecord::Base
belongs_to :attachable, :polymorphic => true
mount_uploader :image, PhotoUploader
end
properties_controller.rb:
def edit
#property = Property.find params[:id]
#property.image.build if #property.image.empty?
end
def update
#property = Property.find params[:id]
if #property.update_attributes params[:property]
redirect_to admin_properties_path, :notice => 'The property has been successfully updated.'
else
render "edit"
end
end
Snippet from properties/_form.html.erb
<%= f.input :image, :label => 'Image:', :as => :file %>
Here is the error I get when submitting with an image attached:
undefined method `each' for #<ActionDispatch::Http::UploadedFile:0x00000102291bb8>
And here are the params:
{"utf8"=>"✓",
"_method"=>"put",
"authenticity_token"=>"lvB7EMdc7juip3gBZD3XhCLyiv1Vwq/hIFdb6f1MtIA=",
"property"=>{"name"=>"Delaware Woods",
"address"=>"",
"city"=>"",
"state"=>"",
"postal_code"=>"",
"description"=>"2 bedroom with large kitchen. Garage available",
"incentives"=>"",
"active"=>"1",
"feature_ids"=>[""],
"user_ids"=>[""],
"image"=>#<ActionDispatch::Http::UploadedFile:0x00000102291bb8 #original_filename="wallpaper-4331.jpg",
#content_type="image/jpeg",
#headers="Content-Disposition: form-data; name=\"property[image]\"; filename=\"wallpaper-4331.jpg\"\r\nContent-Type: image/jpeg\r\n",
#tempfile=#<File:/tmp/RackMultipart20120608-3102-13f3pyv>>},
"commit"=>"Update Property",
"id"=>"18"}
I'm looking everywhere for help on polymorphic associations and am getting nowhere. I've seen simple examples that look pretty straight forward. One thing I've noticed is that it seems like in a lot of the examples the has_many association in my case should be images and not image. However when I do that I get an error:
Can't mass-assign protected attributes: image
I've tried updating my form to use fields_for as I've seen in other blogs like so:
<%= f.input :image, :label => "Photo", :as => :file %>
<% f.simple_fields_for :images do |images_form| %>
<%= images_form.input :id, :as => :hidden %>
<%= images_form.input :attachable_id, :as => :hidden %>
<%= images_form.input :attachable_type, :as => :hidden %>
<%= images_form.input :image, :as => :file %>
<% end %>
All I know is I'm having a heck of a time getting this to work. I'm pretty new to Rails so even debugging it is difficult. It doesn't help that the debugger doesn't really work in 3.2 :(
Since your models have_many :images (it should be :images, not :image), you'll want to use nested_forms in your views. You should set up accepts_nested_attributes_for :images on the unit and property models and change the attr_accessible from :image to :image_attributes.
Check out http://railscasts.com/episodes/196-nested-model-form-part-1 for a good guide on getting going with it.

Rails wants to save an attr_accessor attribute

have some custom attr_accessor in my model.
When I try to create a new model using the params[:model] I'm getting this error:
ActiveModel::MassAssignmentSecurity::Error (Can't mass-assign protected attributes: entity_select, office_select):
class Expedient < ActiveRecord::Base
belongs_to :enterprise
has_many :document
attr_accessor :entity_select
attr_accessor :office_select
...
I suppose Rails know that those are att_accessor and should not be saved on the model in the database.
Or not ?
I'm using this attr_accessor for creating some help field using simple_form:
<%= f.input :entity_select,:label => 'Entity', :input_html => {:class => "span2"}, :wrapper => :prepend do %>
<span class="add-on"><i class="icon-search"></i></span><%= f.input_field :entity_select, :class => "span2 typeahead_entity", :id_selected => '99', :id => 'typeahead_centre'%>
<%end%>
I need a special text input for a typeahed, but I want to create this input using simple_form, like other 'real' fields, that's why I'm using a 'not real attribute'...
thanks,
EDIT:
The error is not when saving, just before, when assigning the params to the model attributes here:
#expedient=Expedient.new.attributes=params[:expedient]
Make the entity_select and office_select attributes accessible:
class Expedient < ActiveRecord::Base
# Add:
attr_accessible :entity_select, :office_select

Embedded Document not being added

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.