Model attribute contains collection of object - ruby-on-rails

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

Related

Rails: delete polymorphic STI has_many through association fails

I have a model called User which has many "taxonomies" associated through a Classification model. One of these taxonomies is a model called Topic (inheriting from Taxonomy). My model User is also called a "classifiable".
EDIT: Added more models to clarify the problem
class User < ActiveRecord::Base
has_many :classifications, :as => :classifiable, :foreign_key => :classifiable_id
has_many :topics, :through => :classifications, :source => :taxonomy, :source_type => "Topic"
end
class Taxonomy < ActiveRecord::Base
end
class Topic < Taxonomy
has_many :classifications, :as => :taxonomy, :foreign_key => :taxonomy_id, :source_type => "Topic"
has_many :professionals, :through => :classifications, :source => :classifiable, :source_type => "User", :conditions => {:is_a_professional => true}
has_many :questions, :through => :classifications, :source => :classifiable, :source_type => "Question"
has_many :guides, :through => :classifications, :source => :classifiable, :source_type => "Guide"
end
class Classification < ActiveRecord::Base
attr_accessible :classifiable, :classifiable_id, :classifiable_type,
:taxonomy, :taxonomy_id, :taxonomy_type
belongs_to :classifiable, :polymorphic => true
belongs_to :taxonomy, :polymorphic => true
end
Everything works well except when I want to delete an association.
user = User.find(12) # any user
topic = user.topics.last # any of his topics
user.topics.delete(topic)
The SQL ActiveRecord runs is the following:
DELETE FROM "classifications" WHERE "classifications"."classifiable_id" = 12 AND "classifications"."classifiable_type" = 'User' AND "classifications"."taxonomy_id" = 34 AND "classifications"."taxonomy_type" = 'Taxonomy'
Clearly, the taxonomy_type is wrong, it should be 'Topic' and not 'Taxonomy'.
Since I am using polymorphic associations and STI, I had to config ActiveRecord as such:
ActiveRecord::Base.store_base_sti_class = false
However, it does not seem to trigger on collection.delete. Is this a bug with rails?

Ruby on Rails has_many_through with validation and logic to ensure only one record in the join table which is updated as required

I have the Course model which has a number of has many through associations with the User model with join table CourseUser. The join table has an attribute type_str which specifies which role the user takes on. I have added validation to ensure that only one record is present in the join table for each course, user pair. The problem is ensuring that this record is updated if it is already present, rather than adding a new one which of course makes validation fail.
User class:
class User < ActiveRecord::Base
...
has_many :courses_enrolled_on, :through => :course_enrollees, :source => :course, :conditions => { :course_users => { :type_str => "enrollee" } }
has_many :course_users
has_many :courses, :through => :course_users, :source => :course, :readonly => true
end
Course class
class Course < ActiveRecord::Base
has_many :course_enrollees, :conditions => { :type_str => "enrollee" }, :class_name => CourseUser
has_many :enrollees, :through => :course_enrollees, :source => :user
has_many :course_users
has_many :users, :through => :course_users, :source => :user, :readonly => true
end
Course class:
class CourseUser < ActiveRecord::Base
belongs_to :course
belongs_to :user
validates_uniqueness_of :course_id, :scope => :user_id
end

How to retrieve ordered objects through a ordered association?

I am using Ruby on Rails 3.2.2. I have following associations:
class Article < ActiveRecord::Base
has_many :category_associations,
:class_name => 'CategoryAssociation'
# Note: Same as :category_associations but gets records ordered by :position.
has_many :positioned_category_associations,
:class_name => 'CategoryAssociation',
:order => :position
has_many :categories,
:through => :category_associations,
:source => :category
# Note: Same as :categories but gets records ordered by :position.
has_many :positioned_categories,
:through => :category_associations,
:source => :category,
:order => [:category_associations => :position]
end
With the above code I can call #article.positioned_categories and get categories properly ordered by position. However, I would like to use the :positioned_category_associations in order to retrieve :positioned_categories but if I state the following:
class Article < ActiveRecord::Base
...
has_many :positioned_categories,
:through => :positioned_category_associations,
:source => :category
# instead of
#
# has_many :positioned_categories,
# :through => :category_associations,
# :source => :category,
# :order => [:category_associations => :position]
end
it seems do not work as expected: I gets not ordered categories.
How to retrieve ordered categories through :positioned_category_associations? Is it possible?
Bonus: Since :category_associations and :positioned_category_associations have almost same statements (except for the :order => :position), is it possible to refactoring :positioned_category_associations statements so to DRY (Don't Repeat Yourself) the code?

ActiveRecord, has_many :through, Polymorphic Associations with STI

In ActiveRecord, has_many :through, and Polymorphic Associations, the OP's example requests ignoring the possible superclass of Alien and Person (SentientBeing). This is where my question lies.
class Widget < ActiveRecord::Base
has_many :widget_groupings
has_many :people, :through => :widget_groupings, :source => :person, :source_type => 'Person'
has_many :aliens, :through => :widget_groupings, :source => :alien, :source_type => 'Alien'
end
SentientBeing < ActiveRecord::Base
has_many :widget_groupings, :as => grouper
has_many :widgets, :through => :widget_groupings
end
class Person < SentientBeing
end
class Alien < SentientBeing
end
In this modified example the grouper_type value for Alien and Person are now both stored by Rails as SentientBeing (Rails seeks out the base class for this grouper_type value).
What is the proper way to modify the has_many's in Widget to filter by type in such a case? I want to be able to do Widget.find(n).people and Widget.find(n).aliens, but currently both of these methods (.people and .aliens) return empty set [] because grouper_type is always SentientBeing.
Have you tried the simplest thing - adding :conditions to the has_many :throughs?
In other words, something like this (in widget.rb):
has_many :people, :through => :widget_groupings, :conditions => { :type => 'Person' }, :source => :grouper, :source_type => 'SentientBeing'
has_many :aliens, :through => :widget_groupings, :conditions => { :type => 'Alien' }, :source => :grouper, :source_type => 'SentientBeing'
JamesDS is correct that a join is needed - but it's not written out here, since the has_many :through association is already doing it.

Relationship Type in Rails

Hi I am very new rails , would need some help , there is nothing similar I could find , i watch all the rail casts on the similar lines.
So I have a article model and user model ( devise ) .
I would to user to add article either in Follow Mode or Just Read Later Mode.
so UserArticleAssociation has article_id , user_id and association type . I am not understanding how to implement this feature correctly. I could make some hack to do these , but I don't want to.
Any tutorial on similar will be great help.
Try this:
class User < ActiveRecord::Base
has_many :user_articles
has_many :read_user_articles, :class_name => "UserArticle",
:conditions => {:mode => "read"}
has_many :follow_user_articles, :class_name => "UserArticle",
:conditions => {:mode => "follow"}
has_many :articles, :through => :user_articles
has_many :read_articles, :through => :read_user_articles, :source => :article
has_many :follow_articles,:through => :follow_user_articles,:source => :article
end
# Add a column called mode of type string (follow, read)
class UserArticle < ActiveRecord::Base
belongs_to :user
belongs_to :article
end
class Article < ActiveRecord::Base
has_many :user_articles
has_many :read_user_articles, :class_name => "UserArticle",
:conditions => {:mode => "read"}
has_many :follow_user_articles, :class_name => "UserArticle",
:conditions => {:mode => "follow"}
has_many :readers, :through => :read_user_articles, :source => :user
has_many :followers,:through => :follow_user_articles,:source => :user
end
Now you can do the following:
To add an article to read/follow category:
user.read_articles << article
user.follow_articles << article
OR
article.reader << user
article.follower << user
To access the articles
user.read_articles
user.follow_articles
To access the users
article.readers
article.followers
You should use has_many :through association. There is a Railscast about it here:
http://railscasts.com/episodes/47-two-many-to-many

Resources