Rails method about foreign keys - ruby-on-rails

I want to delete a company, but there is not dependent: destroy in the model.
Is there an ActiveRecord method on Rails to know which tables are connected to a specific foreign key ?

Using ActiveRecord::reflect_on_all_associations and Array#reject you can filter all has_many association without :dependent key
Company.
reflect_on_all_associations(:has_many).
reject { |association| association.options[:dependent] }
To get table names you can use plural_name attribute
Company.
reflect_on_all_associations(:has_many).
reject { |association| association.options[:dependent] }.
map(&:plural_name)

Related

Rails Associations - Associating a list of items with a particular user for a particular event

I'm working on an event site where users have items in their inventory that can be listed in their profile. For this I am using:
has_many :items
in my user.rb.
A user would then be able to attend any number of events. For each event, they would have a unique items list, i.e., items to bring to the event. I'm trying to figure out the associations in order to make this work.
In item_list.rb:
belongs_to :event
belongs_to :user
has_many :items
In item.rb:
belongs_to :user
belongs_to :item_list
In event.rb
has_many :item_lists
But what's baffling me is making sure that each list is unique to each event and user. Additionally, would my migration for item_list include an array of items?
Any insight would be appreciated.
But what's baffling me is making sure that each list is unique to each
event and user.
If I'm not wrong, you are looking for validates_uniqueness_of with scope option.
In your item_list.rb, add
validates_uniqueness_of :event_id, scope: :user_id
This will ensure you have an item_list with unique event_id and user_id. In other words, each item_list is unique to each event and user.
When I generate my database migration for item_list, would I need to
include a column of arrays, i.e. to hold item_ids
No, with how your associations are setup Rails will expect you to have item_list_id in items table. So if you want fetch items for an item_list, you would do #item_list.items

rails4 scoped has_many association

In my product_users joint table there is a role column besides the product_id and user_id.
I have this association in my product model.
has_many :owners, -> { where(product_users: { role: "owner" }) },
through: :product_users, source: :user
All of the products will have only one "owner" and the rest will be "member".
What association should I use to to get the owner of the product instead of an owners collection. So in the views I wanna use product.owner. I couldn't figure out how to use either has_one or belongs_to.
I could use this instance method, but I guess it would be better to define a fine association somehow.
def owner
owners.first
end
I guess the easiest way to do that, would be to add a column "owner_id" to the product. Then, on the product:
belongs_to :owner
and on the user something like this
has_many :owned_products, class_name: "Product", foreign_key: "owner_id"
The "class_name" tells the association that you will be looking for a "Product" and the foreign_key, will define what column will be used to compare with users id.
If you don't want to add additional column, then you can name association to "has_many :owner", but that's wrong on so many levels, that you shouldn't do it. So in the case you don't want to add additional column, stick to the method.
def owner
owners.first
end

Default dependent action when calling destroy in ActiveRecord / Rails

When calling destroy on a model in ActiveRecord, I've read it is capable of destroying all associated records, and that functionality appears to be setup by using the dependent option when setting up the association.
What I would like to know is - what happens if you don't set the option?
For example, in the below code, am I correct in saying:
The subscribers would NOT be affected
The user would NOT be affected
The comments WOULD be destroyed? (and in turn any associations they have marked with dependent: destroy would also then follow the same process)
class StackOverflowQuestion < ActiveRecord::Base
belongs_to :user
has_many :subscribers
has_many :comments, dependent: :destroy
end
My end goal is to be able to have a model which will destroy some associated records, but not necessarily all of them, as destroying all the associations would mean that data that is reference by other records would start to get wiped out (such as in this example, I'd not want a user to be deleted if their question was deleted).
The subscribers would NOT be affected
This depends on how you define your schema with the foreign key. There are 2 cases here:
Case 1: You define you schema like this:
create_table :subscribers do |t|
t.integer :stack_overflow_question_id
# other fields
end
add_index :subscribers, :stack_overflow_question_id
add_foreign_key :subscribers, :stack_overflow_question, column: :stack_overflow_question_id
This means you set the foreign key constraint for stack_overflow_question_id, so when you delete a StackOverflowQuestion, if there is any Subscriber which has the foreign key referring to that StackOverflowQuestion, rails will give you an error, this makes sense because you are referring a record to a deleted record!
Case 2: Define like Case 1 but without foreign key constraint
Rails won't give you any error, but you will smell wrong with the data, there are some records referring to the deleted records, this should be avoided
The user would NOT be affected
This makes sense because this is belongs_to relation, user wouldn't be affected.
The comments WOULD be destroyed? (and in turn any associations they
have marked with dependent: destroy would also then follow the same
process)
Yes, this is how rails works
Summary
You may redefine like this:
class StackOverflowQuestion < ActiveRecord::Base
belongs_to :user
has_many :subscribers, dependent: :nullify
has_many :comments, dependent: :destroy
end
Hence, your subscribers 's foreign key will be set to NIL when you destroy StackOverflowQuestion, and there isn't any foreign key which is not nil and invalid!
Your description is correct. But you should be aware that the subscribers records will be orphaned. If they are set up with a had_many relation, as you show, then each subscriber record contains a foreign key that is the id of the StackOverflowQuestion record, which will no longer exist after you destroy it. So it will point to an invalid record.

Custom includes association in rails

I have the following table
Users(user_id, name, last_name)
Relationships(user_id, spouse_id)
I want to run the following query
person = Relationships.includes(:person).where(:name => 'David')
But I don't want the related person to be associated by the user_id. I would rather it be associated by the spouse_id only for this specific query.
Rails is perfectly content to allow multiple associations to the same table, providing they use a different foreign key.
In this case, you'd have something like this:
class User
has_many :relationships
has_many :spouses, class_name: "Relationship", foreign_key: :spouse_id
end
User.first.spouses would then be a collection of all relationships where the user's id was present in the spouse_id field.

Rails belongs_to returns nil class

I am trying to link two tables to each other
class Musers < ActiveRecord::Base
# Email
# sid (student_id:integer)
# isyk: boolean
belongs_to :user, :foreign_key => "smail"
end
class Users < ActiveRecord::Base
belongs_to :muser, :foreign_key => "email"
end
But,
#user = Users.first
#user.muser returns nil
By saying :foreign_key => "smail" you are telling rails that the Muser column smail points to the User model's foreign key. This is most likely not the case.
Assuming that the primary key of the User models is called id, you should a user_id field to Muser, and change belongs_to :user, :foreign_key => "smail" into:
belongs_to :user
On the User model you can define the reverse relation using:
has_one :muser
Also, to follow rails model naming conventions, you should rename Users to User and Musers to Muser.
You should read more about belongs_to and has_one.
If, on the other hand, the User model in fact uses email for it's primary key, I would strongly advise you to change that and add an auto-incrementing primary key instead. As a rule of thumb, the primary key should be chosen such that it never changes. If it does change, all foreign keys pointing to that primary key will have to change as well.
You should only use a non auto-incrementing primary key if you have a specific reason for doing so.
More information on choosing a primary key: How to choose my primary key?
Well you can't just tell rails the type of association, you actually have to set the association to an instance of that class. For example, making a new muser will not automatically assign a user as the belongs_to. You could do something like
u = User.new
u.muser = Muser.first
u.save
However, I'm not sure what you are trying to accomplish with a belongs_to - belongs_to relationship, but you should know that you have to do more than just tell rails it exists.

Resources