I have the following relationship. I want a Post to has_one current_wrent but also has_many wrents that keeps tracks of wrent objects. I believe the issue may be related to rails being confused which relationship i'mr eferring to.
When I refer to a post.current_wrent, this is returning correctly with no errors.
Class Post
include Mongoid::Document
include Mongoid::Timestamps
...
has_one :current_wrent, :class_name => "Wrent", :inverse_of => :current_wrent, :autosave => true, :dependent => :destroy
has_many :wrents, :inverse_of => :post, :dependent => :destroy
end
Class Wrent
..
belongs_to :post, :autosave => true
..
end
When I do something like..
(in Wrent.rb)
def accept!
update_attributes!(:status => 1, :accepted => true)
post.current_wrent = self
post.available = false
post.save!
notify_user
end
and I get a "Current Wrent" is invalid error, could somebody point to me something I'm doing wrong here?
EDIT: this seems to work fine.
in wrent.rb
Class Wrent
..
belongs_to :post, :inverse_of => :wrent, :autosave => true
belongs_to :post, :inverse_of => :current_wrent
in post.rb
Class Post
...
has_one :current_wrent, :class_name => "Wrent", :inverse_of => :post
belongs_to :current_wrent, :class_name => "Wrent", :inverse_of => :post
has_many :wrents, :inverse_of => :post, :dependent => :destroy
I'm still not sure what the problem is, but now I can access post.current_wrent through the belongs_to current_wrent_id column and the problem seemed to disappear.
Your Wrent model probably has a post_id field where is stored the id of the Post that it belongs_to. But there's no field in Post to store the current_wrent.
Mongoid allows you to embed objects so what you can do is embeds_one instead has_one.
Class Post
include Mongoid::Document
include Mongoid::Timestamps
...
embeds_one :current_wrent, :class_name => "Wrent", :inverse_of => :current_wrent
has_many :wrents, :inverse_of => :post, :dependent => :destroy
end
Related
I basically wanted to add a condition in the below mentioned associations
class Group < ActiveRecord::Base
has_one :post, :as => :owner, :dependent => :destroy
belongs_to :head_post, :class_name => 'Post', :dependent => :destroy, :foreign_key => 'head_post_id'
end
In posts table I have two records for each group which is post and head_post and I am differentiating between those two using a field in group 'head_post_id'
Something like
has_one :post, :as => :owner, :dependent => :destroy, :conditions => "posts.owner_id != #{self.head_post_id}"
But this doesn't seem to work
Here are my two models
class Answer
include Mongoid::Document
belongs_to :question
has_many :responses
has_many :validations, :dependent => :delete
end
and
class Question
include Mongoid::Document
has_many :answers, :dependent => :delete # it might not always have answers
belongs_to :correct_answer, :class_name => "Answer", :dependent => :delete
end
What is missing here? Not able to resolve it
I have to implement a message model which would have replies for itself. I ended up something like this:
class Message
include Mongoid::Document
belongs_to :sender, :class_name => "User", :inverse_of => :snt_msg
belongs_to :recipient, :class_name => "User", :inverse_of => :rcvd_msg
embeds_many :replies, :class_name => "Message"
embedded_in :message, :inverse_of => :replies
end
and this for user:
class User
include Mongoid::Document
has_many :snt_msg, :class_name => 'Message', :inverse_of => :sender
has_many :rcvd_msg, :class_name => 'Message', :inverse_of => :recipient
end
Is that Ok to work with it, or is there any well-structure design for that?
I have main model Page, which is container.
The page can have some to-do lists, notes, files and discussions. The idea is to have them in special order.
Page.last.container # [Todolist_obj, Note_obj, File_obj, Note_obj, Discussion_obj, File_obj, File_obj]
So I came to approach to use Mongodb
Or I also thought about using Postgres with hstore, but don't know will it help or not
Or maybe just any database and deserialize all objects when getting page, and serialize objects when saving
Or I can make superclass Item and inherit all containing objects from it using MTI and make Page has many relationship.
So I don't know which way is the best?
or perhaps there is a better way?
I have used acts_as_list for implementing sortable objects very successfully. Additionally, i would abstract the elements of a page into a separate model, here called PageElement.
I think there is no need to switch to a NoSQL database (although i have nothing against this approach). Here is a rough sketch of what i'm thinking:
class Page < ActiveRecord::Base
has_many :page_elements, :order => 'position'
has_many :todo_lists, :through => :page_elements, :source => :element, :source_type => 'TodoList'
has_many :notes, :through => :page_elements, :source => :element, :source_type => 'Note'
has_many :files, :through => :page_elements, :source => :element, :source_type => 'File'
has_many :discussions, :through => :page_elements, :source => :element, :source_type => 'Discussion'
end
class PageElement < ActiveRecord::Base
belongs_to :page
belongs_to :element, :polymorphic => true
acts_as_list :scope => :page
end
class TodoList < ActiveRecord::Base
has_one :page_element, :as => :element
has_one :page, :through => :page_elements
end
class Note < ActiveRecord::Base
has_one :page_element, :as => :element
has_one :page, :through => :page_elements
end
class File < ActiveRecord::Base
has_one :page_element, :as => :element
has_one :page, :through => :page_elements
end
class Discussion < ActiveRecord::Base
has_one :page_element, :as => :element
has_one :page, :through => :page_elements
end
This is my model:
class Tag < ActiveRecord::Base
# id, name
has_many :taggings
end
class Tagging < ActiveRecord::Base
# id, tag_id, owner_id, target_type, target_id
belongs_to :tag
belongs_to :owner, :class_name => 'User'
belongs_to :target, :polymorphic => true
validates_uniqueness_of :tag_id, :scope => [ :target_id, :target_type, :owner_id ]
end
class Asset < ActiveRecord::Base
# id, owner_id, title, type, etc
belongs_to :owner, :class_name => 'User'
has_many :taggings, :as => :target
has_many :taggers, :through => :taggings, :source => :owner, :uniq => true
has_many :tags, :through => :taggings, :uniq => true
end
class User < ActiveRecord::Base
# id, name, email, etc
has_many :assets, :foreign_key => 'owner_id'
has_many :my_taggings, :class_name => 'Tagging', :foreign_key => 'owner_id'
has_many :my_tags, :through => :my_taggings, :source => :tag, :uniq => true
has_many :taggings, :as => :target
has_many :taggers, :through => :taggings, :source => :owner, :uniq => true
has_many :tags, :through => :taggings, :uniq => true
end
All of the relations are working but I have an additional requirement that I can't find the solution for:
consider this relation in the Asset class
has_many :tags, :through => :taggings, :uniq => true
calling Asset.find( :first ).tags returns an array of Tags as expected but I need for each Tag to contain a count attribute indicating how many times the row would have appeared if :uniq => true was not specified.
eg. more than one User could apply the same Tag to an Asset. I'd like to display the tag name plus the number of users that applied it.
This should do exactly what you want.
has_many :tags_with_count, :source => :tag, :through => :taggings,
:group => "tags.id", :joins => :taggings,
:select = "tags.*, COUNT('taggings.id') AS frequency"
In terms of rows returned :group => :id will return the same set as :uniq => true, but it will also allow you to perform the calculations you want. This statement is more labour intensive than :uniq => true, so I've given it a different name allowing you to choose whether to fetch the unique tags with their grouped counts, or just the list of unique tags.
The above statement will add the frequency attribute to the records returned. Through the magic of method_missing, you can access that with #tag.frequency.
Usage:
#tags = #asset.tags_with_count
#tags.each{|tag| puts [tag.id, tag.name. tag.frequency].join "\t"}
Will print the id, name, and number of occurrences of each tag for #asset.