rails4 dependent destroy callback error - ruby-on-rails

I have a role attribute on the ProductUser model. Users can be deleted by the owner (role), and I wanna make sure the owner can't delete himself while the product exists. However, when the product gets deleted all the product_users should be gone including the owner.
The following code throws an ActiveRecord::RecordNotDestroyed - Failed to destroy the record error when I try to delete the product. I guess this is because of the order of the execution due to the dependent: :destroy. How can I make this work?
class ProductUser < ActiveRecord::Base
belongs_to :user
belongs_to :product, touch: true
before_destroy :check_for_owner
def check_for_owner
if product && role == "owner" #If I use simply: if role == "owner", it still doesn't work.
errors[:base] << "Owner can't be deleted!"
return false
end
end
end
class Product < ActiveRecord::Base
has_many :product_users, dependent: :destroy
....
end

Have you considered simply not showing the delete button for the ProductUser record if the user is the owner?
In any case, if you use a foreign key rather than dependent destroy then the destroying will happen at the database level and the product user models won't be instantiated which would solve your issue.
So in a migration
def change
add_foreign_key :product_users, :products, on_delete: :cascade
end
Then on product remove the dependent destroy option
class Product < ActiveRecord::Base
has_many :product_users
end
With the on delete cascade option the database will destroy the product's product users when the product is deleted.

Related

How do polymorphic associations get their imageable_id value in the New action?

I'm still having a very difficult time with polymorphic associations, because I can't do nested forms. However, without even getting into forms, I can't even do what I would think is a very basic task.
For example:
#app/models/user.rb
class User < ApplicationRecord
has_many subscriptions, dependent: :destroy, as: :imageable
end
.
#app/models/company.rb
class Company < ApplicationRecord
has_many :subscriptions, dependent: :destroy, as: :imageable
end
.
#app/models/subscription.rb
class Subscription < ApplicationRecord
belongs_to :imageable, polymorphic: true
end
if I run Company.first.subscriptions.create(name: "Random"), this works, but the following fails:
#company = Company.new({:name => "Random Company Name"})
#company.subscriptions.build
#company.save
Why does this fail? It seems because #company.subscriptions shows an associated Subscription with imageable_type: Company but imageable_id: nil. This is a legitimate case where I don't want to add a subscription but I want to add a Company.
If that is the case, then how do I get imageable_id? With a polymorphic association, shouldn't imageable_id get auto filled when #company saves?
I think that when you call
#company = Company.new({:name => "Random Company Name"})
You initialize a new record without saving it, meaning it has an ID of nil.
When you then call
#company.subscriptions.build
It doesn't know what company_id to assign the new subscription. Try changing your first line to:
#company = Company.create({:name => "Random Company Name"})
This will mean #company gets assigned an ID, which can then be assigned to the subscription

How can I establish the link between relational records in belongs_to association?

I would like to create a simple belongs_to association between User and CriminalRecord. A user has only one record and a record belongs to a user. So far I have the following in the corresponding files.
model > user.rb
class User < ActiveRecord::Base
end
models > criminal_record.rb
class CriminalRecord < ActiveRecord::Base
belongs_to :user
end
db > migrate > 20150902003211_create_criminal_records
class CreateCriminalRecords < ActiveRecord::Migration
def change
create_table :criminal_records do |t|
t.belongs_to :user, index: true
t.murderer :boolean
t.thief :boolean
t.timestamps null: false
end
end
end
I am able to create a record for User and a record for CriminalRecord. However, I am unable to accomplish something like this even though I have user_id set to the user's id in the criminal record instance.
User.last.criminal_records
Or for that matter I am unable to do any of the following
john = User.last
john.criminal_record.create(murderer:false, thief: true)
# or
record = CriminalRecord.create(murderer:false, thief: true)
john << record
I get NoMethodError
Define a has_one association in your User model:
class User < ActiveRecord::Base
has_one :criminal_record
end
And, if you already have belongs_to :user in your CriminalRecord Model and user_id column in your criminal_records table, then you are all set.
Then you will be able to do:
john = User.last
john.criminal_record
This is a very simple use case of Active Record Association. I highly recommend you to read the Official Documentation for Active Record Association to know about the available association types and hoe they can be used in Rails application following the proper convention.

Delete children when parent type changes

I have this code:
class FlexField < ActiveRecord::Base
has_many :flex_field_values, class_name: 'FlexFieldValue'
after_save :delete_flex_values
def delete_flex_values
if self.field_type != 'list'
self.flex_field_values.delete_all
end
end
The goal is to delete all values if the type isn't a list. Now what is happening is that as soon as I set the type to something other than list, none of the children get deleted, but their flex_field_id gets set to null.
How can I really have them deleted?
You can write as :
class FlexField < ActiveRecord::Base
has_many :flex_field_values, class_name: 'FlexFieldValue', dependent: :destroy
after_save :delete_flex_values
def delete_flex_values
if self.field_type != 'list'
self.flex_field_values.clear
end
end
end
A brief idea about collection.clear:
Removes every object from the collection. This destroys the associated objects if they are associated with dependent: :destroy, deletes them directly from the database if dependent: :delete_all, otherwise sets their foreign keys to NULL. If the :through option is true no destroy callbacks are invoked on the join models. Join models are directly deleted.

:dependent => :destroy on postgresql uuid

I've a Rails 4 app that uses Postgresql database. I'm using UUIDs as id for my models.
Everything works as expected, I'm trying to set a dependant destroy has many relation, and the "dependant destroy" is not working.
Is there any incompativility between postgress UUIDs and dependent destroy? I need to set foreign keys?
I expalin a bit of my code:
Navigation through models is working correclty
To define the has_many I'm using
has_many :some_models, dependent: :destroy
My migrations are something like:
def change
create_table :my_model, id: :uuid do |t|
To test, I'm using console. I create a relation, delete the "some_models" and the main model is not deleted.
Thanks
You are thinking of the association backwards. dependent: destroy means: When I destroy a parent record, destroy the children that are associated with that record. Here's a contrived example:
class User
has_many :photos, dependent: :destroy
end
When the user is deleted, you want their photos to also be deleted.
If you really want to delete a parent record when a child is deleted, you can do so from the before_destroy callback like so:
class Photo
before_destroy :delete_parent_user
def delete_parent_user
user.destroy if self.user
end
end
Note that other children may still be pointing to that parent record if this is a has_many relationship so this may not be advisable.
dependent: :destroy only destroys child records. When you destroy my_model record, all some_model records belonging to it will be destroyed.

How to retrieve the account id just created with nested methods?

I am using Ruby on Rails 3 and I successfully use nested models in order to save model\object associations.
In the user model file I have:
class User < ActiveRecord::Base
has_one :account
accepts_nested_attributes_for :account
validates_associated :account
end
After #user.save I would like to retrieve the account id just created and save that value in the user database table. I need that because I will use the account_id as the foreign key for the user class, but I don't know if it is possible. If so, how can I do that?
In my user model I also tryed the following:
before_create :initialize_user
def initialize_user
user_account = Account.create
self.account_id = user_account.id
end
but it doesn't work.
UPDATE
I tryed this
class User < ActiveRecord::Base
belongs_to :account,
:class_name => "Account",
:foreign_key => "users_account_id"
end
class Account < ActiveRecord::Base
has_one :user,
:class_name => "User",
:foreign_key => "users_account_id"
end
and it save the new account. Anyway in the user database table the column users_account_id is null and so the foreign_key value isn't saved automatically.
The Approach is wrong. When you have a "has_one" relationship, they foreign key is in the associated model. So in your case it will in account. And if its accepting nested attributes for account. That should be taken care of by default if you are doing it write.
Take a look http://railscasts.com/episodes/196-nested-model-form-part-1 and the other part as well, to see how nested forms work
def initialize_user
user_account = Account.create
self.account_id = user_account.id
end
should be
def initialize_user
self.account.create
end
When the new Account instance is being created, it will use the information about the current user automatically. Your method would have worked, but you'd have needed to add an extra "save" call.

Resources