Change name of mongoid relations (embeds_...,belongs_to,has_...) - ruby

When you have a relation such as embeds_many :album_items which relates to the AlbumItem model. How can I have it stored in just items. I tried embeds_many :album_items, :as => :items and embeds_many :items, :class_name => AlbumItem. Neither worked.
How can I go about renaming the relation?
Thanks

Does this work(assuming your parent model name is Album)?
In Album:
embeds_many :items, :class_name => "AlbumItem", :inverse_of => :album
and in AlbumItem:
embedded_in :album, :class_name => "Album", :inverse_of => :items

Related

Mongoid: Referencing Same Model More Than Once Through has_many

I'd like to be able to reference a model (a has_many relationship) more than once in the same model. For example, given the following models:
class MyModel
include Mongoid::Document
field :name, type: String
has_many :main_efforts, :class_name => 'Effort', as: :effortable, dependent: :delete, autosave: true
has_many :secondary_efforts, :class_name => 'Effort', as: :effortable, dependent: :delete, autosave: true
validates_presence_of :name
end
class Effort
include Mongoid::Document
field :name, type: String
belongs_to :effortable, polymorphic: true
validates_presence_of :name
end
As you can see, the Effort model is referenced twice. Originally, my Effort model wasn't polymorphic, but it seemed Mongoid was unable to determine which collection (main_efforts or secondary_efforts) the effort belonged to. As such, I made it polymorphic. After making it polymorphic, however, my main_efforts and secondary_efforts fields are always an empty array.
What is the proper way to reference a polymorphic model more than once in the same model (assuming a polymorphic model is necessary)?
Figured it out:
class MyModel
include Mongoid::Document
field :name, type: String
has_many :main_efforts, :class_name => 'Effort', dependent: :delete, autosave: true, :inverse_of => :main_effort
has_many :secondary_efforts, :class_name => 'Effort', dependent: :delete, autosave: true, :inverse_of => :secondary_effort
validates_presence_of :name
end
class Effort
include Mongoid::Document
field :name, type: String
belongs_to :main_effort, :class_name => 'Conop', :inverse_of => :main_efforts
belongs_to :secondary_effort, :class_name => 'Conop', :inverse_of => :secondary_efforts
validates_presence_of :name
end

Rails 3 Polymorphic Associations, User model with multiple content items?

In Rails 3 I'm trying to model a user content system, where the user can post different types of content, for example, note, photo, url etc.
From a Java/C# OO perspective, I would use a polymorphic relationship between the User and an interface representing a Content item, e.g. something called IUserContent.
I'm struggling to find an example that works how I expect it to, here's what I tried first, in short I'm getting confused about the implementation of polymorphic associations in ActiveRecord.
# user.rb model - includes...
has_many :notes, :as => :postable, :dependent => :destroy, :inverse_of => :postable
has_many :urls, :as => :postable, :dependent => :destroy, :inverse_of => :postable
has_many :photos, :as => :postable, :dependent => :destroy, :inverse_of => :postable
# url.rb ...
belongs_to :postable, :polymorphic => true, :inverse_of => :urls
# photo.rb
belongs_to :postable, :polymorphic => true, :inverse_of => :photos
# note.rb
belongs_to :postable, :polymorphic => true, :inverse_of => :notes
I'm still just following examples I've found, and frankly this feels like User is the polymorphic target, not the content.
I think I want something like this...
# within user.rb
has_many :postable, :as => :postable, dependent => :destroy, :inverse_of => :users
# photo.rb
# url.rb
# note.rb
# all have the following...
belongs_to :user, :polymorphic => true, :inverse_of => :postable
... looking for a few pointers in the right direction.
Thank you.
The only way you can do that is if all of these classes inherit from the same base class, as in:
class User < ActiveRecord::Base
has_many :postable, :as => :postable, :dependent => :destroy, :class_name => 'Postable'
end
class Postable < ActiveRecord::Base
belongs_to :user, :polymorphic => true
end
class Photo < Postable
end
class Url < Postable
end
class Note < Postable
end
So, you have to use the ActiveRecord single-table inheritance to model such a relationship.

Rails 3, has_many :through and :polymorphic - Should I need to do this?

Ok so here goes. I don't know if I'm over complicating things or if I'm just still so new to Rails that I don't understand the basics. What I want in sudo code is this:
User
has_many projects as owner through relationship
has_many projects as contributor through relationship
has_many projects as follower through relationship
Project
has_one user as owner through relationship
has_many users as followers through relationship
has_many users as contributors through relationship
Relationship
belongs_to user
belongs_to project
Then I'm wanting to have the following magical things:
owner = Project.owner
followers = Project.followers
contributors = Project.contributors
projects = User.projects
myprojects = User.projects... (now I'm really not sure)
followedProjects = ...
contributingProjects = ...
So in writing that down I can see that there is another gap in my understanding of this model. The users can have the role of owner, follower or contributor or any combination of all three.
In terms of real code I have added here what I think is the relevant parts:
class User < ActiveRecord::Base
has_many :user_project_relationships, :as => :relateable, :class_name => "UserProjectRelationship"
has_many :projects, :as => :owner, :through => :relateable, :class_name => "Project", :source_type => :owner
has_many :projects, :as => :follower, :through => :relateable, :class_name => "Project", :source_type => :follower
has_many :projects, :as => :contributor, :through => :relateable, :class_name => "Project", :source_type => :contributor
end
class Project < ActiveRecord::Base
has_many :user_project_relationships, :as => :relateable, :class_name => "UserProjectRelationship"
has_one :user, :as => :owner, :through => :relateable, :class_name => "User"
has_many :users, :as => :followers, :through => :relateable, :source_type => :follower, :class_name => "User"
has_many :users, :as => :contributors, :through => :relateable, :source_type => :contributor, :class_name => "User"
end
class UserProjectRelationship < ActiveRecord::Base
belongs_to :user
belongs_to :project, :polymorphic => true
end
The migration for the relationships model is:
class CreateUserProjectRelationships < ActiveRecord::Migration
def self.up
create_table :user_project_relationships do |t|
t.integer :relateable_id
t.string :relateable_type
t.integer :project_id
t.timestamps
end
add_index :user_project_relationships, [:relateable_id, :relateable_type], :name => :relateable
add_index :user_project_relationships, :project_id
end
def self.down
drop_table :user_project_relationships
end
end
Currently I get errors for things like project.users ActiveRecord::HasManyThroughAssociationNotFoundError: Could not find the association :relateable in model Project
I feel like I'm too in the wilderness here to really get what I want, and maybe relying on magical rails to do more than it does. Any guidance on the best path would be greatly appreciated.
Thanks in advance
Steve
Rails can do alot, but I think instead you're trying to make the Relationship model do too much. Each of those are a different kind of relationship, so I think try to keep them so.
Split that up into separate join models:
class User < ActiveRecord::Base
has_many :owned_projects, :class_name => "Project", :foreign_key => :owner_id
has_many :projects_followers
has_many :followed_projects, :class_name => "Project", :through => :projects_followers
has_many :projects_contributors
has_many :contributed_projects, :class_name => "Project", :through => :projects_contributors
end
class Project < ActiveRecord::Base
belongs_to :owner
has_many :projects_followers
has_many :followers, :class_name => "User", :through => :projects_followers
has_many :projects_contributors, :foreign_key => :contributor_id
has_many :contributors, :class_name => "User", :through => :projects_contributors
end
class ProjectsFollowers < ActiveRecord::Base
belongs_to :user
belongs_to :project
end
class ProjectsContributors < ActiveRecord::Base
belongs_to :user
belongs_to :project
end
Should be a lot closer to what you want. You can then indeed do
project.owner
project.followers
project.contributors
and
user.owned_projects
user.followed_projects
user.contributed_projects
That should either work, or get you pretty close.
I think your mixup came from trying to make a polymorphic relationship, which I don't think is desireable here. AFAI grok, the use case for polymorphic relationships is when you want 1 Model to be related to Any number of other models in the same way. That's not the case here, as you have 2 models with 3 different types of relationships between them.

How do I abstract similar validations/relations to parent class in Ruby/Rails?

I have these VERY similar classes:
class DeliveryDocument < CommercialDocument
# Relations
belongs_to :biller, :class_name => 'Company'
belongs_to :customer, :class_name => 'Company'
belongs_to :customer_center, :class_name => 'Center'
has_many :delivery_document_lines, :dependent => :destroy
alias_attribute :lines, :delivery_document_lines
# Some configuration
accepts_nested_attributes_for :delivery_document_lines
acts_as_freezable :only_dependencies => true,
:has_many => [:delivery_document_lines],
:belongs_to => [:biller, :customer, :customer_center]
acts_as_clonable :has_many => [:delivery_document_lines]
validates_each :lines do |record, attr, value|
# ...
end
end
And:
class InvoiceDocument < CommercialDocument
self.
# Relations
belongs_to :biller, :class_name => 'Company'
belongs_to :customer, :class_name => 'Company'
belongs_to :customer_center, :class_name => 'Center'
has_many :invoice_document_lines, :dependent => :destroy
alias_attribute :lines, :invoice_document_lines
# Some configuration
accepts_nested_attributes_for :invoice_document_lines
acts_as_freezable :only_dependencies => true,
:has_many => [:invoice_document_lines],
:belongs_to => [:biller, :customer, :customer_center]
acts_as_clonable :has_many => [:invoice_document_lines]
# Validations
validates_each :lines do |record, attr, value|
# ...
end
end
I also have some methods I didn't paste that could be extracted to the parent. I only need to know the class name in the parent. When I do this:
class CommercialDocument < Document # document inherits from AR::Base
# ...
has_many :"#{self.to_s.underscore}_lines", :dependent => :destroy
# ...
accepts_nested_attributes_for :"#{self.to_s.underscore}_lines"
# ...
end
it doesn't work, because self.to_s is CommercialDocument.
How would you refactor this behavior in parent class?
I could put things in a module and import it, but then the whole hierarchy of documents becomes almost useless.
I already have the documents' hierarchy, so if I can, I want to use it if there is a way.
You could try using Class.inherited

Mongoid documents inside namespaces

How can I deal with mongoid documents inside namespaces?
I have two mongoid documents as follow:
module A
module B
Class User
include Mongoid::Document
field :name, type: String
has_and_belongs_to_many :groups, :cascade => :nullify, :class_name => 'A::B::Group'
end
Class Group
include Mongoid::Document
field :name, type: String
has_and_belongs_to_many :users, :cascade => :nullify, :class_name => 'A::B::User'
end
end
end
The problem raises when I try to delete a group that contains an user:
u = User.create()
g = Group.create()
g.users << u
at this point u.groups_ids contains the _id of the group g, but when I perform:
g.destroy
It complains of a missing method called 'A/B/groups_ids' in class 'User'.
It is trying to remove the reference of g inside u, but it fails to find the correct namespace...
If I remove the namespaces A and B and the :class_name options everything works fine.
Which is the correct way (if any) to handle namespaces in this scenario?
the solution is to add a :foreign_key => 'A/B/groups_ids':
Class User
include Mongoid::Document
field :name, type: String
has_and_belongs_to_many :groups, :cascade => :nullify, :class_name => 'A::B::Group', :foreign_key => 'A/B/group_ids'
end
Class Group
include Mongoid::Document
field :name, type: String
has_and_belongs_to_many :users, :cascade => :nullify, :class_name => 'A::B::User', :foreign_key => 'A/B/user_ids'
end

Resources