I'm trying to build a model for annotations like the one App.net has: http://developers.app.net/docs/meta/annotations/. To easily add the annotations to many models I use a concern.
So far I have the model for the Annotation:
class Annotation
include Mongoid::Document
field :key, :type => String
field :value
embedded_in :annotatable, polymorphic: true
# Some validations
attr_accessible :key, :value
attr_accessor :key, :value
end
The concern:
module Annotatable
extend ActiveSupport::Concern
included do
embeds_many :annotations, as: :annotatable
end
# Somewhat helper method to add annotaion only after they are valid.
def add_annotation( annotation )
if !annotation.valid?
return false
else
self.annotations.push annotation
return true
end
end
end
And finally there's a model where I include the concern:
class User
include Mongoid::Document
include Mongoid::Timestamps
include Annotatable
# Much other stuff...
end
Unfortunately the annotations won't get saved :-/
Any ideas?
Related
i want to create a concern like this:
module Geolocalizable
extend ActiveSupport::Concern
include Mongoid
included do
attr_accessible :lat, :lng
field :lat
field :lng
end
end
And than include it in my model :
class Store
include Mongoid::Document
include 'Geolocalizable'
field :name, type: String
field :address, type: String
end
But in my stores/new.html.erb
this line gives me an error
f.text_filed :lat
undefined method `lat' for #Store:0xae6bb58
How can i solve this?
I think it's wrong argument type, it should be: include Geolocalizable
I have the following two models:
class Customer
include Mongoid::Document
include Mongoid::Timestamps
embeds_many :locks, class_name: "Lock"
accepts_nested_attributes_for :locks, allow_destroy: true
field :name, type: String
validates :name,
presence: true
belongs_to :list
end
and
class Lock
include Mongoid::Document
include Mongoid::Timestamps
field :locked_by, type: Moped::BSON::ObjectId
embedded_in :customer, inverse_of: :locks, class_name: "Customer"
def unlock!
self.destroy
end
end
So when I try to delete an lock the lock is removed from the child collection but after reload of customer it is still there:
locks = customer.locks.where({ some conditions})
locks.each do |l|
l.unlock!
end
customer.save
The where conditions definitely returns the correct objects.
Can somebody help me and tell me what I did wrong?
Update:
This does not work also
customer.locks = []
customer.save
customer.reload
Well, lets try.
First, delete this block
def unlock!
self.destroy
end
Then, replace
locks = customer.locks.where({ some conditions})
locks.each do |l|
l.unlock!
end
with
customer.locks.where({ some conditions}).delete_all
If still it does not work, please add this one more line after the line above
customer.locks.save
I've set up an ActiveModel class in my Rails app like this:
class MyThingy
extend ActiveModel::Naming
extend ActiveModel::Translation
include ActiveModel::Validations
include ActiveModel::Conversion
attr_accessor :username, :favorite_color, :stuff
def initialize(params)
#Set up stuff
end
end
I really want to be able to do this:
thingy = MyThingy.new(params)
thingy.update_attributes(:favorite_color => :red, :stuff => 'other stuff')
I could just write update_attributes on my own, but I have a feeling it exists somewhere. Does it?
No, but there's common pattern for this case:
class Customer
include ActiveModel::MassAssignmentSecurity
attr_accessor :name, :credit_rating
attr_accessible :name
attr_accessible :name, :credit_rating, :as => :admin
def assign_attributes(values, options = {})
sanitize_for_mass_assignment(values, options[:as]).each do |k, v|
send("#{k}=", v)
end
end
end
It's from here. See the link for examples.
If you find yourself repeating this approach often, you can extract this method into a separate module and include include it on demand.
It looks like they pulled it out of active record and moved it to active model in Rails 5.
http://api.rubyonrails.org/classes/ActiveModel/AttributeAssignment.html#method-i-assign_attributes
You should be able to include the module:
include ActiveModel::AttributeAssignment
I can't seem to figure out why Mongoid won't set the nested attributes for a child object when I create a new parent. I want to create a new Folio, add one child Feature, then push it on the Folios array on Profile.
I have a Profile, which embed many Folios, which embed many Features:
class Profile
include Mongoid::Document
include Mongoid::Timestamps::Updated
#regular fields here; removed for brevity
embeds_many :folios, class_name: "Folio"
end
class Folio
include Mongoid::Document
include Mongoid::Timestamps::Updated
accepts_nested_attributes_for :features
embedded_in :profile
field :name
field :desc
field :order, type: Integer, default:0
embeds_many :features
attr_accessible :name, :desc, :order
end
class Feature
include Mongoid::Document
include Mongoid::Timestamps::Updated
embedded_in :folio
belongs_to :project
field :content_type, type: Integer #ContentType
field :content_id
field :txt, type: String
field :order, type: Integer, default:0
attr_accessible :project_id, :content_type, :content_id, :txt, :order
end
Controller:
def new
#folio = Folio.new
#folio.features.build
end
def create
#folio = Folio.new(params[:folio])
##folio.features is still empty here.
#profile.folios << #folio
#profile.save
render "create_or_update.js"
end
In create, the param hash looks good:
{"folio"=>{"id"=>"new", "name"=>"new name", "desc"=>"new description", "features_attributes"=>{"0"=>{"project_id"=>"4ea0b68e291ebb44a100000a", "content_type"=>"1", "content_id"=>"4ea0b68e291ebb44a100000d", "txt"=>"note here"}}}, "commit"=>"Save", "action"=>"create", "controller"=>"folios"}
But #folio.features is still empty.
This worked fine with AR, if I remember. Strangely, there is no features_attributes=() method on Folio. I thought that was required for the nested attributes to work? What am I missing?
This is on Rails 3.1 with Mongoid 2.2.3.
have you tried enabling AutoSave true for features in Folio document
class Folio
include Mongoid::Document
include Mongoid::Timestamps::Updated
accepts_nested_attributes_for :features , :autosave => true
embedded_in :profile
end
I have a model
class Post
include Mongoid::Document
include Mongoid::Timestamps
embeds_one :comment
end
and I have comment class
class Comment
include Mongoid::Document
include Mongoid::Timestamps
embedded_in :post
field :title
field :description
end
And I have another class inherited from comment
class RecentComment < Comment
# certain methods
end
Now I want to be able to create RecentComment through post if I do Post.last.build_comment(:_type => "RecentComment") the new comment will not be of _type:"RecentComment", and similarly if I do Post.last.build_recent_comment, it gives me error saying sth like undefined method build_recent_comment for Post class. If the post had references_many :comments I should have done Post.last.build_comments({}, RecentComment) without any problems. But I don't know about how to build an object with RecentComment class in this case. If anybody could help that'd be gr8!
Note: I am using gem 'mongoid', '~> 2.0.1'
Maybe try
class Post
include Mongoid::Document
include Mongoid::Timestamps
embeds_one :recent_comment, :class_name => Comment
and just make your Comment class polymorphic
class Comment
include Mongoid::Document
include Mongoid::Timestamps
field :type
validates_inclusion_of :type, :in => ["recent", "other"]
one option is to try something like:
class RecentComment < Comment
store_in "comment"
#set the type you want
end
but you might just use timestamps
and scope to retrieve your recent,
old comment, new_comment and such,
like within the comment class
scope :recent, where("created_at > (Time.now - 1.day)")
then you can do:
post.comments.recent