i have an association for a user as user has_many agents and agent belongs_to user.
in rails console,i am trying to use different users to test a particular scenario and i want a user with no agents,hence i want to delete the user.agents.
i tried user.agents.map(&:destroy),but it gives error as ActiveRecord::StaleObjectError: Attempted to delete a stale object.i even tried user.agents.delete_all but it too does not work.can i delete the users agents with a single command in rails console.
You better use destroy because it goes through all the Rails magic (callbacks and such)
user.destroy #For a single record
user.agents.destroy_all #For a collection
You are looking for a .destroy_all method. It destroys all records of a given collection.
So user.agents.destroy_all, would return an empty array for user.agents.
You could not have used .delete_all because it is a class method and it deletes records that match a given condition. Like this, Agent.delete_all(condition). If used without a condition it deletes all records from a matched table.
Keep in mind that .destroy methods are instance methods. They instantiate an object and perform callbacks before erasing it. .delete methods are class methods and they directly erase an object.
This works for me
user.agents.find_each(&:destroy)
ActiveRecord::StaleObjectError
Is for Optimistic locking, remove any locks you have on it before trying to delete again. Check if anyone else is using the system or submit any forms you have open.
Related
I am trying to create a Rails app and I have a database consisting of author and a quotation by that author.
Now different users can choose to destroy or kill quotations from the database however it must only be deleted for that particular user i.e other users should still be able to see quotes that they didn't delete even if another user did.
I know that I would need to implement cookies but other than that I am unsure how to proceed. Can anyone point me to a tutorial or give me some pointers to get started on this complex task?
You surely have a User model in your application - one 'Rails-like' way to go about this would be to add a has_and_belongs_to_many relationship between User and Quotation.
This creates a relationship between each individual user and 'their' quotations. This relationship can be deleted without actually deleting a quotation, so all quotations would still be available to other users. If you want each user to be able to see all quotations by default, you would need to set up the relationship in advance.
Assuming you are using Devise to log your users in, all you'd need to do then is to replace Quotation.all with current_user.quotations in whichever controller you are using to display quotations.
The Rails guide linked above is quite helpful but basically you just need to add something like the following:
class User
has_and_belongs_to_many :quotations
before_create :add_quotations
def add_quotations
self.quotations << Quotation.all
end
#etc...
end
class Quotation
has_and_belongs_to_many :users
#etc...
end
and then run a migration adding a new table called users_quotations with the columns user_id and quotation_id.
EDIT
As #Yule pointed out this wouldn't let users see any quotations that were created after they were, and it would be quite annoying to have to set up the join tables in advance, so a more efficient way would be to have an excluded_quotations join table instead. So users can see all quotations except the ones that they have excluded.
I have a model relation of dependant=>destroy that has to do 50K+ deletes when the destroy is triggered. Looking at the console, rails is trying to do an explicit delete with ID for every single row, which is taking a while. Is there a way for me to force rails to do a bulk delete? Or, I can remove the model dependency, is there a way to do this kind of bulk delete from the code?
Thanks
You should be able to set dependent: delete_all
If you can't get that to work, you might want to use delete_all in your own callback.
To be clear, delete_all should generate a single statement to delete all child objects
I am learning Rails and I am reading the Beginning Rails 3 book. When you have a has_many association you automatically receives methods.
Let say user has many articles.
user.articles.delete(article)
Now that line only set the foreign key of the article to "NULL". Is it correct that you also must destroy/delete the article if you want it to disappear from the database, or is there a method that does it both?
And what happens if you destroy an article that is in a relationship with a user before you delete the association?
There are some difference between delete and destroy.
The delete method essentially deletes a row.. that's it..
On the other hand, destroy allows you more options:
it will check any callbacks such as before_delete, or any dependencies specified on the model.
it will also keep the object that just got deleted in memory; So it allows you to leave a message saying for example: “Article #{article.id} deleted!!”
And the answer for your question: it will delete any child objects associated with the object.
So, instead of
user.articles.delete(article)
you can use
user.articles.destroy(article)
In this way you will prevent any orphaned rows on the database.
I am working on a project that has the following cucumber step:
Given /^no registered users$/ do
User.delete_all
end
As a new RoR user this looks a little dangerous even though I'd be testing on our development database because our User table has actual data. What is the line of code doing?
Thanks!
delete_all is from activerecord library not from FactoryGirl.
And the difference between these two is :
delete_all(conditions = nil) public
Deletes the records matching conditions without instantiating the records first, and hence not calling the destroy method nor invoking callbacks.
This is a single SQL DELETE statement that goes straight to the database, much more efficient than destroy_all.
Be careful with relations though, in particular :dependent rules defined on associations are not honored.
Returns the number of rows affected.
destroy_all(conditions = nil) public
Destroys the records matching conditions by instantiating each record and calling its destroy method.
Each object’s callbacks are executed (including :dependent association options and before_destroy/after_destroy Observer methods).
Returns the collection of objects that were destroyed; each will be frozen, to reflect that no changes should be made (since they can’t be persisted).
Note
Instantiation, callback execution, and deletion of each record can be time consuming when you’re removing many records at once. It generates at least one SQL DELETE query per record . If you want to delete many rows quickly, without concern for their associations or callbacks, use delete_all instead.
delete_all is not from FactoryGirl, it is an active record command and it deletes the users from your database. If you are running this from cucumber then it should run against your test database, not development.
A better alternative is destroy_all since that version will run any associated callbacks. For example, if users have posts, and you have a before_destroy callback to remove posts if users are deleted.
Here's a link to more info about delete_all
delete_all will forceably remove records from the corresponding table without activating any rails callbacks.
destroy_all will remove the records but also call the model callbacks
Based on your example, it's probably deleting all users in order to allow the next Cucumber step to register new users. The ActiveRecord::Base#delete_all method says, in part:
Deletes the records matching conditions without instantiating the
records first, and hence not calling the destroy method nor invoking
callbacks. This is a single SQL DELETE statement that goes straight to
the database, much more efficient than destroy_all.
There are probably better ways to write that test, but the intent is clearly to remove the user records as efficiently as possible.
As for it being dangerous, your tests should be running against the test database, not the development or production databases. Since it's possible to misconfigure your testing framework to use the wrong database, you could certainly add a step or conditional that tests if Rails.env.test? is true. That's a fairly small price to pay for peace of mind.
I am implementing a User that is not actually deleted from the system with destroy but only marked with :active = false.
The problem here is that such an inactivate user will show up in all User.find, User.all, ... calls. I don't want to pollute the code with all kinds of 'if-else's or overwriting the behavior of .find, .all etc.
I just want to know whether I can nicely define it within the User's model so that inactive users will virtually disappear unless I explicitly want to extract such a user.
If there is no way to do it in the model then what are my options?
Use a scope, or a class method with a where clause.
I think you may want to check acts_as_paranoid Here is a link for one of the implementations: https://github.com/technoweenie/acts_as_paranoid
From the wiki:
Now whenever destroy is called on that model, it is just removed from view and the deleted_at column set to the current date time. All the finder methods ignore “deleted” records.