Delete a model present in another namespace rails - ruby-on-rails

In Rails when I have made one Model as the foreign key in another model then I can delete that model while speciying its relation like:
class User < ApplicationRecord
has_many :garments, dependent: :destroy
end
But if I have one model which is created in another namespace like superadmin them how to write the dependent destroy relation in that case
for example I am using :
class User < ApplicationRecord
has_one superadmin::company , dependent: :destroy
end
which is incorrect.
The model company is present in namespace superadmin, please tell if their is a correct a way possible. Thanks in advance

It's incorrect, Way of reference to model and namespace with class name is incorrect:
incorrrect:
class User < ApplicationRecord
has_one superadmin::company , dependent: :destroy
end
corrrect:
class User < ApplicationRecord
has_one :company, :class_name => "Superadmin::Company", :dependent => :destroy
end

class User < ApplicationRecord
has_one :company, :class_name => "Superadmin::Company", :dependent => :destroy
#has_many :companies, :class_name => "Superadmin::Company", :dependent => :destroy
end

Related

ActiveRecord - Bi-directional :dependent => :destroy on has_many <-> belongs_to association

In a rails 4 application with a has_many belongs_to association, how should bi-directional :dependent => :destroy functionality be implemented?
Using Contact and Organisation as an example. The desired behaviour is as follows:
Destroying an organisation destroys the organisation and all of the associated contacts.
Destroying a contact associated to an organisation with multiple contacts destroys only the contact.
Destroying the last contact associated to an organisation destroys the contact and the associated organisation.
Setting :dependent => :destroy on the has_many satisfies conditions 1 and 2, but not 3.
class Organisation < ActiveRecord::Base
has_many :contacts, :dependent => :destroy
end
class Contact < ActiveRecord::Base
belongs_to :organisation
end
Setting :dependent => :destroy on the belongs_to satisfies conditions 1 and 3, but not 2.
class Organisation < ActiveRecord::Base
has_many :contacts
end
class Contact < ActiveRecord::Base
belongs_to :organisation, :dependent => :destroy
end
What's the cleanest way to achieve this behaviour?
I've found a solution that achieves the desired behaviour without setting :dependent => :destroy:
class Organisation < ActiveRecord::Base
has_many :contacts
def destroy
self.contacts.delete_all if self.contacts.any?
super
end
class Contact < ActiveRecord::Base
belongs_to :organisation
after_destroy :cascade_destroy
private
def cascade_destroy
self.organisation.destroy if self.organisation.contacts.empty?
end
end
Rather than overriding the Organisation#destroy I had tried setting :dependent => :destroy on the has_many :contacts association, however I believe this created an infinite loop, as it caused the app to throw a 'stack level too deep' error.
Calling self.contacts.delete_all seems to avoid that issue, although I don't know why.

Get attribute value from the join in a many-to-many relationship

I have a many-to-many relation between User and "Link".
The join model is called LinkAddress and besides for saving the IDs of the other two models, it has an attribute called address - information it collects at creation.
How can I access the address attribute for a certain link in a request scenario like the following: User.first.links.first.address ?
Models:
class User < ActiveRecord::Base
has_many :link_addresses, dependent: :destroy
has_many :links, through: :link_addresses
accepts_nested_attributes_for :link_addresses, allow_destroy: true
end
class LinkAddress < ActiveRecord::Base
belongs_to :user
belongs_to :link
end
class Link < ActiveRecord::Base
has_many :link_addresses, dependent: :destroy
has_many :users, through: :link_addresses
end
You could access it through User since it's a has_many ... :through relation:
User.first.link_addresses.first.address
Or, if you'd like to go through links then:
User.first.links.first.link_addresses.first.address
SQL Aliases
I had this exact question: Rails Scoping For has_many :through To Access Extra Data
Here's the answer I got:
#Images
has_many :image_messages, :class_name => 'ImageMessage'
has_many :images, -> { select("#{Image.table_name}.*, #{ImageMessage.table_name}.caption AS caption") }, :class_name => 'Image', :through => :image_messages, dependent: :destroy
This uses SQL Aliases which I found at this RailsCast (at around 6:40 in). It allows us to call #user.image.caption (even though .caption is in the join model)
Your Code
For your query, I'd use this:
class User < ActiveRecord::Base
has_many :link_addresses, dependent: :destroy
has_many :links, -> { select("#{Link.table_name}.*, #{LinkAddress.table_name}.address AS address") }, through: :link_addresses
accepts_nested_attributes_for :link_addresses, allow_destroy: true
end
This will allow you to write #user.links.first.address, and gracefully handles an absence of the address record

many to many relation by Users and Files and ownership of it in rails

How can I add ownership in many to many relationships?
For example like this models.
class User < ActiveRecord::Base
has_many :editabilities, dependent: :destroy
has_many :files, through: :editabilities
end
class File < ActiveRecord::Base
has_many :editabilities, dependent: :destroy
has_many :users, through: :editabilities
end
class Editabilities < ActiveRecord::Base
belongs_to :user
belongs_to :file
end
And I want to add a one-to-many relationship to User-and-Files.
At first I thought it is best to add owner boolean column to Editabilities, but I have no idea how to handle it.
Secondly I thought if I make a new junction model Ownerships, then I can handle it same way as Editabilities. But I've got a uninitialized constant User::Ownership when I tried it with code like this.
class User < ActiveRecord::Base
has_many :editabilities, dependent: :destroy
has_many :ownerships, dependent: :destroy
has_many :files, through: :editabilities
has_many :owned_files, through: :ownerships, source: :file
end
class File < ActiveRecord::Base
has_many :editabilities, dependent: :destroy
has_many :ownerships, dependent: :destroy
has_many :users, through: :editabilities
has_one :owner, through: :ownerships, source: :user
end
class Editabilities < ActiveRecord::Base
belongs_to :user
belongs_to :file
end
class Ownerships < ActiveReord::Base
belongs_to :user
belongs_to :file
end
How can I implement a feature like this?
The only problems I see here are the classes Editabilities and Ownerships. By Rails convention model class names should be singular, not plural.
class Editability < ActiveRecord::Base
belongs_to :user
belongs_to :file
end
class Ownership < ActiveReord::Base
belongs_to :user
belongs_to :file
end
One way to quickly check your class names is by checking the result of the classify function:
> "editibilities".classify
=> "Editibility"
> "ownerships".classify
=> "Ownership"
The rest of the associations all look correct.
Your class should be named Ownership and not Ownerships.
ActiveRecord class names are normally singular and table names are plural.
Easier solution seems to add belongs_to association to File model. Because 1 File can have only 1 owner.
class File < ActiveRecord::Base
...
belongs_to :owner, class_name: 'User'
end
You will need to add owner_id column to files table.

How do I model these relationships?

I have a contact model, this includes name, address, phone number, etc.
I have a user model which should have_one contact.
I have a Customer model which has_many contacts.
I have a Producer model which has many contacts.
A contact can be only a user, a user and a customer, a user and a producer, or any combination of these three. I also need to be sure that the same contact record is linked when a contact is linked to multiple models for data integrity.
how should I create the associations?
This looks like a good application for a polymorphic association:
class User < ActiveRecord::Base
has_one :contact, :as => :contactable
end
class Customer < ActiveRecord::Base
has_many :contacts, :as => :contactable
end
class Producer < ActiveRecord::Base
has_many :contacts, :as => :contactable
end
class Contact < ActiveRecord::Base
belongs_to :contactable, :polymorphic => true
end
EDIT
It seems I didn't read the specs all the way through :) To associate the same contact with multiple Users, Customers, etc, you could use a has_many :through:
class User < ActiveRecord::Base
has_one :user_contact, :dependent => :destroy
has_one :contact, :through => :user_contact
end
class Customer < ActiveRecord::Base
has_many :customer_contacts, :dependent => :destroy
has_many :contacts, :through => :customer_contacts
end
class Producer < ActiveRecord::Base
has_many :producer_contacts, :dependent => :destroy
has_many :contacts, :through => :producer_contacts
end
class UserContact
belongs_to :user
belongs_to :contact
end
class CustomerContact
belongs_to :customer
belongs_to :contact
end
class ProducerContact
belongs_to :producer
belongs_to :contact
end
class Contact < ActiveRecord::Base
has_many :user_contacts, :dependent => :destroy # might use 'has_one' here depending on your requirements
has_many :users, :through => :user_contacts
has_many :customer_contacts, :dependent => :destroy
has_many :customers, :through => :customer_contacts
has_many :producer_contacts, :dependent => :destroy
has_many :producers, :through => :producer_contacts
end
That gives you one join table for each of the three associations. Each Contact can belong to none, one, or many of the three other models by adding rows to the join tables.

how to avoid duplicates in a has_many :through relationship?

How can I achieve the following? I have two models (blogs and readers) and a JOIN table that will allow me to have an N:M relationship between them:
class Blog < ActiveRecord::Base
has_many :blogs_readers, :dependent => :destroy
has_many :readers, :through => :blogs_readers
end
class Reader < ActiveRecord::Base
has_many :blogs_readers, :dependent => :destroy
has_many :blogs, :through => :blogs_readers
end
class BlogsReaders < ActiveRecord::Base
belongs_to :blog
belongs_to :reader
end
What I want to do now, is add readers to different blogs. The condition, though, is that I can only add a reader to a blog ONCE. So there mustn't be any duplicates (same readerID, same blogID) in the BlogsReaders table. How can I achieve this?
The second question is, how do I get a list of blog that the readers isn't subscribed to already (e.g. to fill a drop-down select list, which can then be used to add the reader to another blog)?
Simpler solution that's built into Rails:
class Blog < ActiveRecord::Base
has_many :blogs_readers, :dependent => :destroy
has_many :readers, :through => :blogs_readers, :uniq => true
end
class Reader < ActiveRecord::Base
has_many :blogs_readers, :dependent => :destroy
has_many :blogs, :through => :blogs_readers, :uniq => true
end
class BlogsReaders < ActiveRecord::Base
belongs_to :blog
belongs_to :reader
end
Note adding the :uniq => true option to the has_many call.
Also you might want to consider has_and_belongs_to_many between Blog and Reader, unless you have some other attributes you'd like to have on the join model (which you don't, currently). That method also has a :uniq opiton.
Note that this doesn't prevent you from creating the entries in the table, but it does ensure that when you query the collection you get only one of each object.
Update
In Rails 4 the way to do it is via a scope block. The Above changes to.
class Blog < ActiveRecord::Base
has_many :blogs_readers, dependent: :destroy
has_many :readers, -> { uniq }, through: :blogs_readers
end
class Reader < ActiveRecord::Base
has_many :blogs_readers, dependent: :destroy
has_many :blogs, -> { uniq }, through: :blogs_readers
end
class BlogsReaders < ActiveRecord::Base
belongs_to :blog
belongs_to :reader
end
Update for Rails 5
The use of uniq in the scope block will cause an error NoMethodError: undefined method 'extensions' for []:Array. Use distinct instead :
class Blog < ActiveRecord::Base
has_many :blogs_readers, dependent: :destroy
has_many :readers, -> { distinct }, through: :blogs_readers
end
class Reader < ActiveRecord::Base
has_many :blogs_readers, dependent: :destroy
has_many :blogs, -> { distinct }, through: :blogs_readers
end
class BlogsReaders < ActiveRecord::Base
belongs_to :blog
belongs_to :reader
end
This should take care of your first question:
class BlogsReaders < ActiveRecord::Base
belongs_to :blog
belongs_to :reader
validates_uniqueness_of :reader_id, :scope => :blog_id
end
The Rails 5.1 way
class Blog < ActiveRecord::Base
has_many :blogs_readers, dependent: :destroy
has_many :readers, -> { distinct }, through: :blogs_readers
end
class Reader < ActiveRecord::Base
has_many :blogs_readers, dependent: :destroy
has_many :blogs, -> { distinct }, through: :blogs_readers
end
class BlogsReaders < ActiveRecord::Base
belongs_to :blog
belongs_to :reader
end
What about:
Blog.find(:all,
:conditions => ['id NOT IN (?)', the_reader.blog_ids])
Rails takes care of the collection of ids for us with association methods! :)
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
The answer at this link shows how to override the "<<" method to achieve what you are looking for without raising exceptions or creating a separate method: Rails idiom to avoid duplicates in has_many :through
The top answer currently says to use uniq in the proc:
class Blog < ActiveRecord::Base
has_many :blogs_readers, dependent: :destroy
has_many :readers, -> { uniq }, through: :blogs_readers
end
This however kicks the relation into an array and can break things that are expecting to perform operations on a relation, not an array.
If you use distinct it keeps it as a relation:
class Blog < ActiveRecord::Base
has_many :blogs_readers, dependent: :destroy
has_many :readers, -> { distinct }, through: :blogs_readers
end
I'm thinking someone will come along with a better answer than this.
the_reader = Reader.find(:first, :include => :blogs)
Blog.find(:all,
:conditions => ['id NOT IN (?)', the_reader.blogs.map(&:id)])
[edit]
Please see Josh's answer below. It's the way to go. (I knew there was a better way out there ;)
I do the following for Rails 6
class BlogsReaders < ActiveRecord::Base
belongs_to :blog
belongs_to :reader
validates :blog_id, uniqueness: { scope: :reader_id }
end
Don't forget to create database constraint to prevent violations of a uniqueness.
Easiest way is to serialize the relationship into an array:
class Blog < ActiveRecord::Base
has_many :blogs_readers, :dependent => :destroy
has_many :readers, :through => :blogs_readers
serialize :reader_ids, Array
end
Then when assigning values to readers, you apply them as
blog.reader_ids = [1,2,3,4]
When assigning relationships this way, duplicates are automatically removed.

Resources